summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: af2ed61)
raw | patch | inline | side by side (parent: af2ed61)
author | Florian Forster <ff@octo.it> | |
Wed, 16 Jun 2010 15:13:28 +0000 (17:13 +0200) | ||
committer | Florian Forster <octo@leeloo.lan.home.verplant.org> | |
Wed, 16 Jun 2010 15:13:28 +0000 (17:13 +0200) |
68 files changed:
AUTHORS | [new file with mode: 0644] | patch | blob |
ChangeLog | [new file with mode: 0644] | patch | blob |
Makefile | [deleted file] | patch | blob | history |
Makefile.am | [new file with mode: 0644] | patch | blob |
NEWS | [new file with mode: 0644] | patch | blob |
README | [new file with mode: 0644] | patch | blob |
action_graph.c | [deleted file] | patch | blob | history |
action_graph.h | [deleted file] | patch | blob | history |
action_list_graphs.c | [deleted file] | patch | blob | history |
action_list_graphs.h | [deleted file] | patch | blob | history |
aux_types.h | [deleted file] | patch | blob | history |
common.c | [deleted file] | patch | blob | history |
common.h | [deleted file] | patch | blob | history |
configure.ac | [new file with mode: 0644] | patch | blob |
filesystem.c | [deleted file] | patch | blob | history |
filesystem.h | [deleted file] | patch | blob | history |
graph.c | [deleted file] | patch | blob | history |
graph.h | [deleted file] | patch | blob | history |
graph_config.c | [deleted file] | patch | blob | history |
graph_config.h | [deleted file] | patch | blob | history |
graph_def.c | [deleted file] | patch | blob | history |
graph_def.h | [deleted file] | patch | blob | history |
graph_ident.c | [deleted file] | patch | blob | history |
graph_ident.h | [deleted file] | patch | blob | history |
graph_instance.c | [deleted file] | patch | blob | history |
graph_instance.h | [deleted file] | patch | blob | history |
graph_list.c | [deleted file] | patch | blob | history |
graph_list.h | [deleted file] | patch | blob | history |
oconfig.c | [deleted file] | patch | blob | history |
oconfig.h | [deleted file] | patch | blob | history |
parser.y | [deleted file] | patch | blob | history |
scanner.l | [deleted file] | patch | blob | history |
src/Makefile.am | [new file with mode: 0644] | patch | blob |
src/action_graph.c | [new file with mode: 0644] | patch | blob |
src/action_graph.h | [new file with mode: 0644] | patch | blob |
src/action_list_graphs.c | [new file with mode: 0644] | patch | blob |
src/action_list_graphs.h | [new file with mode: 0644] | patch | blob |
src/aux_types.h | [new file with mode: 0644] | patch | blob |
src/common.c | [new file with mode: 0644] | patch | blob |
src/common.h | [new file with mode: 0644] | patch | blob |
src/filesystem.c | [new file with mode: 0644] | patch | blob |
src/filesystem.h | [new file with mode: 0644] | patch | blob |
src/graph.c | [new file with mode: 0644] | patch | blob |
src/graph.h | [new file with mode: 0644] | patch | blob |
src/graph_config.c | [new file with mode: 0644] | patch | blob |
src/graph_config.h | [new file with mode: 0644] | patch | blob |
src/graph_def.c | [new file with mode: 0644] | patch | blob |
src/graph_def.h | [new file with mode: 0644] | patch | blob |
src/graph_ident.c | [new file with mode: 0644] | patch | blob |
src/graph_ident.h | [new file with mode: 0644] | patch | blob |
src/graph_instance.c | [new file with mode: 0644] | patch | blob |
src/graph_instance.h | [new file with mode: 0644] | patch | blob |
src/graph_list.c | [new file with mode: 0644] | patch | blob |
src/graph_list.h | [new file with mode: 0644] | patch | blob |
src/main.c | [new file with mode: 0644] | patch | blob |
src/oconfig.c | [new file with mode: 0644] | patch | blob |
src/oconfig.h | [new file with mode: 0644] | patch | blob |
src/parser.y | [new file with mode: 0644] | patch | blob |
src/scanner.l | [new file with mode: 0644] | patch | blob |
src/utils_array.c | [new file with mode: 0644] | patch | blob |
src/utils_array.h | [new file with mode: 0644] | patch | blob |
src/utils_params.c | [new file with mode: 0644] | patch | blob |
src/utils_params.h | [new file with mode: 0644] | patch | blob |
test.fcgi.c | [deleted file] | patch | blob | history |
utils_array.c | [deleted file] | patch | blob | history |
utils_array.h | [deleted file] | patch | blob | history |
utils_params.c | [deleted file] | patch | blob | history |
utils_params.h | [deleted file] | patch | blob | history |
diff --git a/ChangeLog b/ChangeLog
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ /dev/null
@@ -1,54 +0,0 @@
-CC = gcc
-CPPFLAGS =
-CFLAGS = -Wall -Wextra -O0 -g
-LDFLAGS =
-LDLIBS =
-
-all: test.fcgi
-
-clean:
- rm -f test.cgi
-
-common.o: common.c common.h
-
-filesystem.o: filesystem.c filesystem.h
-
-graph.o: graph.c graph.h
-
-graph_config.o: graph_config.c graph_config.h
-
-graph_def.o: graph_def.c graph_def.h
-
-graph_ident.o: graph_ident.c graph_ident.h
-
-graph_instance.o: graph_instance.c graph_instance.h
-
-graph_list.o: graph_list.c graph_list.h
-
-utils_array.o: utils_array.c utils_array.h
-
-utils_params.o: utils_params.c utils_params.h
-
-action_graph.o: action_graph.c action_graph.h
-
-action_list_graphs.o: action_list_graphs.c action_list_graphs.h
-
-oconfig.o: oconfig.c oconfig.h
-
-scanner.c: scanner.l
- flex --outfile=scanner.c scanner.l
-
-scanner.o: scanner.c parser.h
-
-parser.c parser.h: parser.y
- bison --output=parser.c --defines=parser.h parser.y
-
-parser.o: parser.c
-
-test: test.c utils_params.o
-
-test.fcgi: LDLIBS = -lfcgi -lrrd
-test.fcgi: test.fcgi.c common.o filesystem.o graph.o graph_config.o graph_def.o graph_ident.o graph_instance.o graph_list.o utils_array.o utils_params.o action_graph.o action_list_graphs.o scanner.o parser.o oconfig.o
-
-.PHONY: clean
-
diff --git a/action_graph.c b/action_graph.c
--- a/action_graph.c
+++ /dev/null
@@ -1,150 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <dirent.h> /* for PATH_MAX */
-#include <assert.h>
-#include <math.h>
-
-#include <rrd.h>
-
-#include "common.h"
-#include "action_graph.h"
-#include "graph_list.h"
-#include "utils_params.h"
-#include "utils_array.h"
-
-#include <fcgiapp.h>
-#include <fcgi_stdio.h>
-
-static void emulate_graph (int argc, char **argv) /* {{{ */
-{
- int i;
-
- printf ("rrdtool \\\n");
- for (i = 0; i < argc; i++)
- {
- if (i < (argc - 1))
- printf (" \"%s\" \\\n", argv[i]);
- else
- printf (" \"%s\"\n", argv[i]);
- }
-} /* }}} void emulate_graph */
-
-static int ag_info_print (rrd_info_t *info) /* {{{ */
-{
- if (info->type == RD_I_VAL)
- printf ("[info] %s = %g;\n", info->key, info->value.u_val);
- else if (info->type == RD_I_CNT)
- printf ("[info] %s = %lu;\n", info->key, info->value.u_cnt);
- else if (info->type == RD_I_STR)
- printf ("[info] %s = %s;\n", info->key, info->value.u_str);
- else if (info->type == RD_I_INT)
- printf ("[info] %s = %i;\n", info->key, info->value.u_int);
- else if (info->type == RD_I_BLO)
- printf ("[info] %s = [blob, %lu bytes];\n", info->key, info->value.u_blo.size);
- else
- printf ("[info] %s = [unknown type %#x];\n", info->key, info->type);
-
- return (0);
-} /* }}} int ag_info_print */
-
-static int output_graph (rrd_info_t *info) /* {{{ */
-{
- rrd_info_t *img;
-
- for (img = info; img != NULL; img = img->next)
- if ((strcmp ("image", img->key) == 0)
- && (img->type == RD_I_BLO))
- break;
-
- if (img == NULL)
- return (ENOENT);
-
- printf ("Content-Type: image/png\n"
- "Content-Length: %lu\n"
- "\n",
- img->value.u_blo.size);
- fwrite (img->value.u_blo.ptr, img->value.u_blo.size,
- /* nmemb = */ 1, stdout);
-
- return (0);
-} /* }}} int output_graph */
-
-#define OUTPUT_ERROR(...) do { \
- printf ("Content-Type: text/plain\n\n"); \
- printf (__VA_ARGS__); \
- return (0); \
-} while (0)
-
-int action_graph (void) /* {{{ */
-{
- str_array_t *args;
- graph_config_t *cfg;
- graph_instance_t *inst;
- rrd_info_t *info;
- int status;
-
- cfg = gl_graph_get_selected ();
- if (cfg == NULL)
- OUTPUT_ERROR ("gl_graph_get_selected () failed.\n");
-
- inst = inst_get_selected (cfg);
- if (inst == NULL)
- OUTPUT_ERROR ("inst_get_selected (%p) failed.\n", (void *) cfg);
-
- args = array_create ();
- if (args == NULL)
- return (ENOMEM);
-
- array_append (args, "graph");
- array_append (args, "-");
- array_append (args, "--imgformat");
- array_append (args, "PNG");
-
- status = inst_get_rrdargs (cfg, inst, args);
- if (status != 0)
- {
- array_destroy (args);
- OUTPUT_ERROR ("inst_get_rrdargs failed with status %i.\n", status);
- }
-
- rrd_clear_error ();
- info = rrd_graph_v (array_argc (args), array_argv (args));
- if ((info == NULL) || rrd_test_error ())
- {
- printf ("Content-Type: text/plain\n\n");
- printf ("rrd_graph_v failed: %s\n", rrd_get_error ());
- emulate_graph (array_argc (args), array_argv (args));
- }
- else
- {
- int status;
-
- status = output_graph (info);
- if (status != 0)
- {
- rrd_info_t *ptr;
-
- printf ("Content-Type: text/plain\n\n");
- printf ("output_graph failed. Maybe the \"image\" info was not found?\n\n");
-
- for (ptr = info; ptr != NULL; ptr = ptr->next)
- {
- ag_info_print (ptr);
- }
- }
- }
-
- if (info != NULL)
- rrd_info_free (info);
-
- array_destroy (args);
- args = NULL;
-
- return (0);
-} /* }}} int action_graph */
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/action_graph.h b/action_graph.h
--- a/action_graph.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef ACTION_GRAPH_H
-#define ACTION_GRAPH_H 1
-
-int action_graph (void);
-
-#endif /* ACTION_GRAPH_H */
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/action_list_graphs.c b/action_list_graphs.c
--- a/action_list_graphs.c
+++ /dev/null
@@ -1,126 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-
-#include "action_list_graphs.h"
-#include "graph.h"
-#include "graph_list.h"
-#include "utils_params.h"
-
-#include <fcgiapp.h>
-#include <fcgi_stdio.h>
-
-static int print_graph_inst_json (__attribute__((unused)) graph_config_t *cfg, /* {{{ */
- graph_instance_t *inst,
- void *user_data)
-{
- _Bool *first;
- graph_ident_t *ident;
- char *json;
-
- first = user_data;
-
- ident = inst_get_selector (inst);
- if (ident == NULL)
- return (-1);
-
- json = ident_to_json (ident);
- if (json == NULL)
- {
- ident_destroy (ident);
- return (ENOMEM);
- }
-
- if (*first)
- printf ("%s", json);
- else
- printf (",\n%s", json);
-
- *first = 0;
-
- ident_destroy (ident);
- return (0);
-} /* }}} int print_graph_inst_json */
-
-static int print_graph_json (graph_config_t *cfg, /* {{{ */
- void *user_data)
-{
- return (gl_graph_instance_get_all (cfg, print_graph_inst_json, user_data));
-} /* }}} int print_graph_json */
-
-static int list_graphs_json (void) /* {{{ */
-{
- _Bool first = 1;
-
- printf ("Content-Type: application/json\n\n");
-
- printf ("[\n");
- gl_graph_get_all (print_graph_json, /* user_data = */ &first);
- printf ("\n]");
-
- return (0);
-} /* }}} int list_graphs_json */
-
-static int print_graph_inst_html (graph_config_t *cfg, /* {{{ */
- graph_instance_t *inst,
- __attribute__((unused)) void *user_data)
-{
- char params[1024];
- char desc[1024];
-
- memset (params, 0, sizeof (params));
- inst_get_params (cfg, inst, params, sizeof (params));
-
- memset (desc, 0, sizeof (desc));
- inst_describe (cfg, inst, desc, sizeof (desc));
-
- printf (" <li><a href=\"test.fcgi?action=graph;%s\">%s</a></li>\n",
- params, desc);
-
- return (0);
-} /* }}} int print_graph_inst_html */
-
-static int print_graph_html (graph_config_t *cfg, /* {{{ */
- __attribute__((unused)) void *user_data)
-{
- char buffer[1024];
-
- memset (buffer, 0, sizeof (buffer));
- graph_get_title (cfg, buffer, sizeof (buffer));
-
- printf (" <li>%s\n <ul>\n", buffer);
- gl_graph_instance_get_all (cfg, print_graph_inst_html, /* user_data = */ NULL);
- printf (" </ul></li>\n");
-
- return (0);
-} /* }}} int print_graph_html */
-
-static int list_graphs_html (void) /* {{{ */
-{
- printf ("Content-Type: text/html\n\n");
-
- printf ("<ul>\n");
- gl_graph_get_all (print_graph_html, /* user_data = */ NULL);
- printf ("</ul>\n");
-
- return (0);
-} /* }}} int list_graphs_html */
-
-int action_list_graphs (void) /* {{{ */
-{
- const char *format;
-
- gl_update ();
-
- format = param ("format");
- if (format == NULL)
- format = "html";
-
- if (strcmp ("json", format) == 0)
- return (list_graphs_json ());
- else
- return (list_graphs_html ());
-} /* }}} int action_list_graphs */
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/action_list_graphs.h b/action_list_graphs.h
--- a/action_list_graphs.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef ACTION_LIST_GRAPHS_H
-#define ACTION_LIST_GRAPHS_H 1
-
-int action_list_graphs (void);
-
-#endif /* ACTION_LIST_GRAPHS_H */
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/aux_types.h b/aux_types.h
--- a/aux_types.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef AUX_TYPES_H
-#define AUX_TYPES_H 1
-
-struct statement_list_s
-{
- oconfig_item_t *statement;
- int statement_num;
-};
-typedef struct statement_list_s statement_list_t;
-
-struct argument_list_s
-{
- oconfig_value_t *argument;
- int argument_num;
-};
-typedef struct argument_list_s argument_list_t;
-
-#endif /* AUX_TYPES_H */
diff --git a/common.c b/common.c
--- a/common.c
+++ /dev/null
@@ -1,193 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <assert.h>
-#include <math.h>
-
-#include <rrd.h>
-
-#include "common.h"
-#include "graph_list.h"
-
-#include <fcgiapp.h>
-#include <fcgi_stdio.h>
-
-size_t c_strlcat (char *dst, const char *src, size_t size) /* {{{ */
-{
- size_t retval;
- size_t dst_len;
- size_t src_len;
-
- dst_len = strlen (dst);
- src_len = strlen (src);
- retval = dst_len + src_len;
-
- if ((dst_len + 1) >= size)
- return (retval);
-
- dst += dst_len;
- size -= dst_len;
- assert (size >= 2);
-
- /* Result will be truncated. */
- if (src_len >= size)
- src_len = size - 1;
-
- memcpy (dst, src, src_len);
- dst[src_len] = 0;
-
- return (retval);
-} /* }}} size_t c_strlcat */
-
-int ds_list_from_rrd_file (char *file, /* {{{ */
- size_t *ret_dses_num, char ***ret_dses)
-{
- char *rrd_argv[] = { "info", file, NULL };
- int rrd_argc = (sizeof (rrd_argv) / sizeof (rrd_argv[0])) - 1;
-
- rrd_info_t *info;
- rrd_info_t *ptr;
-
- char **dses = NULL;
- size_t dses_num = 0;
-
- info = rrd_info (rrd_argc, rrd_argv);
- if (info == NULL)
- {
- printf ("%s: rrd_info (%s) failed.\n", __func__, file);
- return (-1);
- }
-
- for (ptr = info; ptr != NULL; ptr = ptr->next)
- {
- size_t keylen;
- size_t dslen;
- char *ds;
- char **tmp;
-
- if (strncmp ("ds[", ptr->key, strlen ("ds[")) != 0)
- continue;
-
- keylen = strlen (ptr->key);
- if (keylen < strlen ("ds[?].index"))
- continue;
-
- dslen = keylen - strlen ("ds[].index");
- assert (dslen >= 1);
-
- if (strcmp ("].index", ptr->key + (strlen ("ds[") + dslen)) != 0)
- continue;
-
- ds = malloc (dslen + 1);
- if (ds == NULL)
- continue;
-
- memcpy (ds, ptr->key + strlen ("ds["), dslen);
- ds[dslen] = 0;
-
- tmp = realloc (dses, sizeof (*dses) * (dses_num + 1));
- if (tmp == NULL)
- {
- free (ds);
- continue;
- }
- dses = tmp;
-
- dses[dses_num] = ds;
- dses_num++;
- }
-
- rrd_info_free (info);
-
- if (dses_num < 1)
- {
- assert (dses == NULL);
- return (ENOENT);
- }
-
- *ret_dses_num = dses_num;
- *ret_dses = dses;
-
- return (0);
-} /* }}} int ds_list_from_rrd_file */
-
-static int hsv_to_rgb (double *hsv, double *rgb) /* {{{ */
-{
- double c = hsv[2] * hsv[1];
- double h = hsv[0] / 60.0;
- double x = c * (1.0 - fabs (fmod (h, 2.0) - 1));
- double m = hsv[2] - c;
-
- rgb[0] = 0.0;
- rgb[1] = 0.0;
- rgb[2] = 0.0;
-
- if ((0.0 <= h) && (h < 1.0)) { rgb[0] = 1.0; rgb[1] = x; rgb[2] = 0.0; }
- else if ((1.0 <= h) && (h < 2.0)) { rgb[0] = x; rgb[1] = 1.0; rgb[2] = 0.0; }
- else if ((2.0 <= h) && (h < 3.0)) { rgb[0] = 0.0; rgb[1] = 1.0; rgb[2] = x; }
- else if ((3.0 <= h) && (h < 4.0)) { rgb[0] = 0.0; rgb[1] = x; rgb[2] = 1.0; }
- else if ((4.0 <= h) && (h < 5.0)) { rgb[0] = x; rgb[1] = 0.0; rgb[2] = 1.0; }
- else if ((5.0 <= h) && (h < 6.0)) { rgb[0] = 1.0; rgb[1] = 0.0; rgb[2] = x; }
-
- rgb[0] += m;
- rgb[1] += m;
- rgb[2] += m;
-
- return (0);
-} /* }}} int hsv_to_rgb */
-
-static uint32_t rgb_to_uint32 (double *rgb) /* {{{ */
-{
- uint8_t r;
- uint8_t g;
- uint8_t b;
-
- r = (uint8_t) (255.0 * rgb[0]);
- g = (uint8_t) (255.0 * rgb[1]);
- b = (uint8_t) (255.0 * rgb[2]);
-
- return ((((uint32_t) r) << 16)
- | (((uint32_t) g) << 8)
- | ((uint32_t) b));
-} /* }}} uint32_t rgb_to_uint32 */
-
-uint32_t get_random_color (void) /* {{{ */
-{
- double hsv[3] = { 0.0, 1.0, 1.0 };
- double rgb[3] = { 0.0, 0.0, 0.0 };
-
- hsv[0] = 360.0 * ((double) rand ()) / (((double) RAND_MAX) + 1.0);
-
- hsv_to_rgb (hsv, rgb);
-
- return (rgb_to_uint32 (rgb));
-} /* }}} uint32_t get_random_color */
-
-int print_debug (const char *format, ...) /* {{{ */
-{
- static _Bool have_header = 0;
-
- va_list ap;
- int status;
-
- if (!have_header)
- {
- printf ("Content-Type: text/plain\n\n");
- have_header = 1;
- }
-
- va_start (ap, format);
- status = vprintf (format, ap);
- va_end (ap);
-
- return (status);
-} /* }}} int print_debug */
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/common.h b/common.h
--- a/common.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef COMMON_H
-#define COMMON_H 1
-
-#include <stdint.h>
-#include <inttypes.h>
-
-int print_debug (const char *format, ...)
- __attribute__((format(printf,1,2)));
-#if 0
-# define DEBUG(...) print_debug (__VA_ARGS__)
-#else
-# define DEBUG(...) /**/
-#endif
-
-size_t c_strlcat (char *dst, const char *src, size_t size);
-#define strlcat c_strlcat
-
-int ds_list_from_rrd_file (char *file,
- size_t *ret_dses_num, char ***ret_dses);
-
-uint32_t get_random_color (void);
-
-#endif /* COMMON_H */
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/configure.ac b/configure.ac
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,33 @@
+AC_INIT(collection, 4.0.0)
+AC_CONFIG_SRCDIR(src/main.c)
+AC_CONFIG_HEADERS(src/config.h)
+AM_INIT_AUTOMAKE(dist-bzip2)
+AC_LANG(C)
+
+AC_PREFIX_DEFAULT("/opt/collection4")
+
+#
+# Check for programs/utilities
+#
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LEX
+AC_PROG_YACC
+AM_CONDITIONAL(COMPILER_IS_GCC, test "x$GCC" = "xyes")
+
+#
+# Checks for header files.
+#
+AC_HEADER_STDC
+AC_CHECK_HEADERS(stdbool.h sys/types.h sys/socket.h netdb.h)
+
+AC_CHECK_HEADERS(fcgiapp.h fcgi_stdio.h rrd.h, [],
+ [AC_MSG_ERROR(a required header file cannot be found.)])
+
+AC_CHECK_LIB(fcgi, FCGI_Accept, [],
+ [AC_MSG_ERROR(cannot find libfcgi.)])
+AC_CHECK_LIB(rrd_th, rrd_graph_v, [],
+ [AC_MSG_ERROR(cannot find librrd_th.)], [-lm])
+
+AC_OUTPUT(Makefile src/Makefile)
diff --git a/filesystem.c b/filesystem.c
--- a/filesystem.c
+++ /dev/null
@@ -1,297 +0,0 @@
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h>
-
-#include "filesystem.h"
-
-struct fs_scan_dir_data_s /* {{{ */
-{
- fs_ident_cb_t callback;
- void *user_data;
-
- char *host;
- char *plugin;
- char *plugin_instance;
- char *type;
- char *type_instance;
-}; /* }}} */
-typedef struct fs_scan_dir_data_s fs_scan_dir_data_t;
-
-typedef int (*callback_type_t) (const char *type, void *user_data);
-typedef int (*callback_plugin_t) (const char *plugin, void *user_data);
-typedef int (*callback_host_t) (const char *host, void *user_data);
-
-/*
- * Directory and file walking functions
- */
-static int foreach_rrd_file (const char *dir, /* {{{ */
- int (*callback) (const char *, void *),
- void *user_data)
-{
- DIR *dh;
- struct dirent *entry;
- int status;
-
- if (callback == NULL)
- return (EINVAL);
-
- dh = opendir (dir);
- if (dh == NULL)
- return (errno);
-
- while ((entry = readdir (dh)) != NULL)
- {
- struct stat statbuf;
- char abspath[PATH_MAX + 1];
- size_t d_name_len;
-
- if (entry->d_name[0] == '.')
- continue;
-
- d_name_len = strlen (entry->d_name);
- if (d_name_len <= 4)
- continue;
-
- if (strcasecmp (".rrd", entry->d_name + (d_name_len - 4)) != 0)
- continue;
-
- snprintf (abspath, sizeof (abspath), "%s/%s", dir, entry->d_name);
- abspath[sizeof (abspath) - 1] = 0;
-
- memset (&statbuf, 0, sizeof (statbuf));
-
- status = stat (abspath, &statbuf);
- if (status != 0)
- continue;
-
- if (!S_ISREG (statbuf.st_mode))
- continue;
-
- entry->d_name[d_name_len - 4] = 0;
-
- status = (*callback) (entry->d_name, user_data);
- if (status != 0)
- break;
- } /* while (readdir) */
-
- closedir (dh);
- return (status);
-} /* }}} int foreach_rrd_file */
-
-static int foreach_dir (const char *dir, /* {{{ */
- int (*callback) (const char *, void *),
- void *user_data)
-{
- DIR *dh;
- struct dirent *entry;
- int status = 0;
-
- if (callback == NULL)
- return (EINVAL);
-
- dh = opendir (dir);
- if (dh == NULL)
- return (errno);
-
- while ((entry = readdir (dh)) != NULL)
- {
- struct stat statbuf;
- char abspath[PATH_MAX + 1];
-
- if (entry->d_name[0] == '.')
- continue;
-
- snprintf (abspath, sizeof (abspath), "%s/%s", dir, entry->d_name);
- abspath[sizeof (abspath) - 1] = 0;
-
- memset (&statbuf, 0, sizeof (statbuf));
-
- status = stat (abspath, &statbuf);
- if (status != 0)
- continue;
-
- if (!S_ISDIR (statbuf.st_mode))
- continue;
-
- status = (*callback) (entry->d_name, user_data);
- if (status != 0)
- break;
- } /* while (readdir) */
-
- closedir (dh);
- return (status);
-} /* }}} int foreach_dir */
-
-static int foreach_type (const char *host, const char *plugin, /* {{{ */
- callback_type_t callback, void *user_data)
-{
- char abspath[PATH_MAX + 1];
-
- if ((host == NULL) || (plugin == NULL))
- return (EINVAL);
-
- snprintf (abspath, sizeof (abspath), "%s/%s/%s", DATA_DIR, host, plugin);
- abspath[sizeof (abspath) - 1] = 0;
-
- return (foreach_rrd_file (abspath, callback, user_data));
-} /* }}} int foreach_type */
-
-static int foreach_plugin (const char *host, /* {{{ */
- callback_plugin_t callback,
- void *user_data)
-{
- char abspath[PATH_MAX + 1];
-
- if (host == NULL)
- return (EINVAL);
-
- snprintf (abspath, sizeof (abspath), "%s/%s", DATA_DIR, host);
- abspath[sizeof (abspath) - 1] = 0;
-
- return (foreach_dir (abspath, callback, user_data));
-} /* }}} int foreach_plugin */
-
-static int foreach_host (callback_host_t callback, /* {{{ */
- void *user_data)
-{
- return (foreach_dir (DATA_DIR, callback, user_data));
-} /* }}} int foreach_host */
-
-/*
- * Functions building "fs_scan_dir_data_t" and calling the user-supplied
- * callback eventually.
- */
-static int scan_type (const char *type, void *user_data) /* {{{ */
-{
- fs_scan_dir_data_t *data = user_data;
- graph_ident_t *ident;
- int status;
-
- if ((type == NULL) || (data == NULL))
- return (EINVAL);
-
- if ((data->type != NULL) || (data->type_instance != NULL))
- return (EINVAL);
-
- data->type = strdup (type);
- if (data->type == NULL)
- return (ENOMEM);
-
- data->type_instance = strchr (data->type, '-');
- if (data->type_instance != NULL)
- {
- *data->type_instance = 0;
- data->type_instance++;
- }
- else
- {
- data->type_instance = data->type + strlen (data->type);
- }
-
- ident = ident_create (data->host,
- data->plugin, data->plugin_instance,
- data->type, data->type_instance);
- if (ident == NULL)
- {
- status = -1;
- }
- else
- {
- status = (*data->callback) (ident, data->user_data);
- ident_destroy (ident);
- }
-
- free (data->type);
- data->type = NULL;
- data->type_instance = NULL;
-
- return (status);
-} /* }}} int scan_type */
-
-static int scan_plugin (const char *plugin, void *user_data) /* {{{ */
-{
- fs_scan_dir_data_t *data = user_data;
- int status;
-
- if ((plugin == NULL) || (data == NULL))
- return (EINVAL);
-
- if ((data->plugin != NULL) || (data->plugin_instance != NULL))
- return (EINVAL);
-
- data->plugin = strdup (plugin);
- if (data->plugin == NULL)
- return (ENOMEM);
-
- data->plugin_instance = strchr (data->plugin, '-');
- if (data->plugin_instance != NULL)
- {
- *data->plugin_instance = 0;
- data->plugin_instance++;
- }
- else
- {
- data->plugin_instance = data->plugin + strlen (data->plugin);
- }
-
- status = foreach_type (data->host, plugin, scan_type, data);
-
- free (data->plugin);
- data->plugin = NULL;
- data->plugin_instance = NULL;
-
- return (status);
-} /* }}} int scan_plugin */
-
-static int scan_host (const char *host, void *user_data) /* {{{ */
-{
- fs_scan_dir_data_t *data = user_data;
- int status;
-
- if ((host == NULL) || (data == NULL))
- return (EINVAL);
-
- if (data->host != NULL)
- return (EINVAL);
-
- data->host = strdup (host);
- if (data->host == NULL)
- return (ENOMEM);
-
- status = foreach_plugin (host, scan_plugin, data);
-
- free (data->host);
- data->host = NULL;
-
- return (status);
-} /* }}} int scan_host */
-
-/*
- * Public function
- */
-int fs_scan (fs_ident_cb_t callback, void *user_data) /* {{{ */
-{
- fs_scan_dir_data_t data;
-
- memset (&data, 0, sizeof (data));
- data.callback = callback;
- data.user_data = user_data;
-
- data.host = NULL;
- data.plugin = NULL;
- data.plugin_instance = NULL;
- data.type = NULL;
- data.type_instance = NULL;
-
- foreach_host (scan_host, &data);
-
- return (0);
-} /* }}} int fs_scan */
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/filesystem.h b/filesystem.h
--- a/filesystem.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef FILESYSTEM_G
-#define FILESYSTEM_G 1
-
-#include "graph_ident.h"
-
-#define DATA_DIR "/var/lib/collectd/rrd"
-
-typedef int (*fs_ident_cb_t) (const graph_ident_t *ident, void *user_data);
-
-int fs_scan (fs_ident_cb_t callback, void *user_data);
-
-#endif /* FILESYSTEM_G */
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/graph.c b/graph.c
--- a/graph.c
+++ /dev/null
@@ -1,290 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <string.h>
-#include <time.h>
-#include <errno.h>
-#include <assert.h>
-
-#include "graph.h"
-#include "graph_list.h"
-#include "graph_ident.h"
-#include "graph_def.h"
-#include "graph_config.h"
-#include "common.h"
-#include "filesystem.h"
-#include "utils_params.h"
-
-#include <fcgiapp.h>
-#include <fcgi_stdio.h>
-
-/*
- * Data types
- */
-struct graph_config_s /* {{{ */
-{
- graph_ident_t *select;
-
- char *title;
- char *vertical_label;
-
- graph_def_t *defs;
-
- graph_instance_t *instances;
-}; /* }}} struct graph_config_s */
-
-/*
- * Private functions
- */
-static graph_instance_t *graph_find_instance (graph_config_t *cfg, /* {{{ */
- const graph_ident_t *ident)
-{
- if ((cfg == NULL) || (ident == NULL))
- return (NULL);
-
- return (inst_find_matching (cfg->instances, ident));
-} /* }}} graph_instance_t *graph_find_instance */
-
-/*
- * Config functions
- */
-static graph_ident_t *graph_config_get_selector (const oconfig_item_t *ci) /* {{{ */
-{
- char *host = NULL;
- char *plugin = NULL;
- char *plugin_instance = NULL;
- char *type = NULL;
- char *type_instance = NULL;
- graph_ident_t *ret;
- int i;
-
- for (i = 0; i < ci->children_num; i++)
- {
- oconfig_item_t *child;
-
- child = ci->children + i;
-
- if (strcasecmp ("Host", child->key) == 0)
- graph_config_get_string (child, &host);
- else if (strcasecmp ("Plugin", child->key) == 0)
- graph_config_get_string (child, &plugin);
- else if (strcasecmp ("PluginInstance", child->key) == 0)
- graph_config_get_string (child, &plugin_instance);
- else if (strcasecmp ("Type", child->key) == 0)
- graph_config_get_string (child, &type);
- else if (strcasecmp ("TypeInstance", child->key) == 0)
- graph_config_get_string (child, &type_instance);
- /* else: ignore all other directives here. */
- } /* for */
-
- ret = ident_create (host, plugin, plugin_instance, type, type_instance);
-
- free (host);
- free (plugin);
- free (plugin_instance);
- free (type);
- free (type_instance);
-
- return (ret);
-} /* }}} int graph_config_get_selector */
-
-/*
- * Global functions
- */
-graph_config_t *graph_create (const graph_ident_t *selector) /* {{{ */
-{
- graph_config_t *cfg;
-
- cfg = malloc (sizeof (*cfg));
- if (cfg == NULL)
- return (NULL);
- memset (cfg, 0, sizeof (*cfg));
-
- if (selector != NULL)
- cfg->select = ident_clone (selector);
- else
- cfg->select = NULL;
-
- cfg->title = NULL;
- cfg->vertical_label = NULL;
- cfg->defs = NULL;
- cfg->instances = NULL;
-
- return (cfg);
-} /* }}} int graph_create */
-
-void graph_destroy (graph_config_t *cfg) /* {{{ */
-{
- if (cfg == NULL)
- return;
-
- ident_destroy (cfg->select);
-
- free (cfg->title);
- free (cfg->vertical_label);
-
- def_destroy (cfg->defs);
- inst_destroy (cfg->instances);
-} /* }}} void graph_destroy */
-
-int graph_config_add (const oconfig_item_t *ci) /* {{{ */
-{
- graph_ident_t *select;
- graph_config_t *cfg = NULL;
- int i;
-
- select = graph_config_get_selector (ci);
- if (select == NULL)
- return (EINVAL);
-
- cfg = graph_create (/* selector = */ NULL);
- if (cfg == NULL)
- return (ENOMEM);
-
- cfg->select = select;
-
- for (i = 0; i < ci->children_num; i++)
- {
- oconfig_item_t *child;
-
- child = ci->children + i;
-
- if (strcasecmp ("Title", child->key) == 0)
- graph_config_get_string (child, &cfg->title);
- else if (strcasecmp ("VerticalLabel", child->key) == 0)
- graph_config_get_string (child, &cfg->vertical_label);
- else if (strcasecmp ("DEF", child->key) == 0)
- def_config (cfg, child);
- } /* for */
-
- gl_add_graph (cfg);
-
- return (0);
-} /* }}} graph_config_add */
-
-int graph_add_file (graph_config_t *cfg, const graph_ident_t *file) /* {{{ */
-{
- graph_instance_t *inst;
-
- inst = graph_find_instance (cfg, file);
- if (inst == NULL)
- {
- inst = inst_create (cfg, file);
- if (inst == NULL)
- return (ENOMEM);
-
- if (cfg->instances == NULL)
- cfg->instances = inst;
- else
- inst_append (cfg->instances, inst);
- }
-
- return (inst_add_file (inst, file));
-} /* }}} int graph_add_file */
-
-int graph_get_title (graph_config_t *cfg, /* {{{ */
- char *buffer, size_t buffer_size)
-{
- if ((cfg == NULL) || (buffer == NULL) || (buffer_size < 1))
- return (EINVAL);
-
- if (cfg->title == NULL)
- cfg->title = ident_to_string (cfg->select);
-
- if (cfg->title == NULL)
- return (ENOMEM);
-
- strncpy (buffer, cfg->title, buffer_size);
- buffer[buffer_size - 1] = 0;
-
- return (0);
-} /* }}} int graph_get_title */
-
-graph_ident_t *graph_get_selector (graph_config_t *cfg) /* {{{ */
-{
- if (cfg == NULL)
- return (NULL);
-
- return (ident_clone (cfg->select));
-} /* }}} graph_ident_t *graph_get_selector */
-
-graph_instance_t *graph_get_instances (graph_config_t *cfg) /* {{{ */
-{
- if (cfg == NULL)
- return (NULL);
-
- return (cfg->instances);
-} /* }}} graph_instance_t *graph_get_instances */
-
-graph_def_t *graph_get_defs (graph_config_t *cfg) /* {{{ */
-{
- if (cfg == NULL)
- return (NULL);
-
- return (cfg->defs);
-} /* }}} graph_def_t *graph_get_defs */
-
-int graph_add_def (graph_config_t *cfg, graph_def_t *def) /* {{{ */
-{
- if ((cfg == NULL) || (def == NULL))
- return (EINVAL);
-
- if (cfg->defs == NULL)
- {
- cfg->defs = def;
- return (0);
- }
-
- return (def_append (cfg->defs, def));
-} /* }}} int graph_add_def */
-
-_Bool graph_matches (graph_config_t *cfg, const graph_ident_t *ident) /* {{{ */
-{
- if ((cfg == NULL) || (ident == NULL))
- return (0);
-
- return (ident_matches (cfg->select, ident));
-} /* }}} _Bool graph_matches */
-
-int graph_compare (graph_config_t *cfg, const graph_ident_t *ident) /* {{{ */
-{
- if ((cfg == NULL) || (ident == NULL))
- return (0);
-
- return (ident_compare (cfg->select, ident));
-} /* }}} int graph_compare */
-
-int graph_clear_instances (graph_config_t *cfg) /* {{{ */
-{
- if (cfg == NULL)
- return (EINVAL);
-
- inst_destroy (cfg->instances);
- cfg->instances = NULL;
-
- return (0);
-} /* }}} int graph_clear_instances */
-
-int graph_get_rrdargs (graph_config_t *cfg, graph_instance_t *inst, /* {{{ */
- str_array_t *args)
-{
- if ((cfg == NULL) || (inst == NULL) || (args == NULL))
- return (EINVAL);
-
- if (cfg->title != NULL)
- {
- array_append (args, "-t");
- array_append (args, cfg->title);
- }
-
- if (cfg->vertical_label != NULL)
- {
- array_append (args, "-v");
- array_append (args, cfg->vertical_label);
- }
-
- return (0);
-} /* }}} int graph_get_rrdargs */
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/graph.h b/graph.h
--- a/graph.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef GRAPH_H
-#define GRAPH_H 1
-
-/*
- * Data types
- */
-struct graph_config_s;
-typedef struct graph_config_s graph_config_t;
-
-#include "graph_def.h"
-#include "graph_ident.h"
-#include "graph_instance.h"
-#include "oconfig.h"
-#include "utils_array.h"
-
-/*
- * Functions
- */
-graph_config_t *graph_create (const graph_ident_t *selector);
-
-void graph_destroy (graph_config_t *graph);
-
-int graph_config_add (const oconfig_item_t *ci);
-
-int graph_add_file (graph_config_t *cfg, const graph_ident_t *file);
-
-int graph_get_title (graph_config_t *cfg,
- char *buffer, size_t buffer_size);
-
-graph_ident_t *graph_get_selector (graph_config_t *cfg);
-
-graph_instance_t *graph_get_instances (graph_config_t *cfg);
-
-graph_def_t *graph_get_defs (graph_config_t *cfg);
-
-int graph_add_def (graph_config_t *cfg, graph_def_t *def);
-
-_Bool graph_matches (graph_config_t *cfg, const graph_ident_t *ident);
-
-int graph_compare (graph_config_t *cfg, const graph_ident_t *ident);
-
-int graph_clear_instances (graph_config_t *cfg);
-
-int graph_get_rrdargs (graph_config_t *cfg, graph_instance_t *inst,
- str_array_t *args);
-
-#endif /* GRAPH_H */
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/graph_config.c b/graph_config.c
--- a/graph_config.c
+++ /dev/null
@@ -1,116 +0,0 @@
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <strings.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-
-#include "graph_config.h"
-#include "graph_list.h"
-#include "oconfig.h"
-#include "common.h"
-
-#define CONFIG_FILE "/usr/lib/cgi-bin/octo/collection.conf"
-
-time_t last_read_mtime = 0;
-
-static int dispatch_config (const oconfig_item_t *ci) /* {{{ */
-{
- int i;
-
- for (i = 0; i < ci->children_num; i++)
- {
- oconfig_item_t *child;
-
- child = ci->children + i;
- if (strcasecmp ("Graph", child->key) == 0)
- graph_config_add (child);
- else
- {
- DEBUG ("Unknown config option: %s", child->key);
- }
- }
-
- return (0);
-} /* }}} int dispatch_config */
-
-static int internal_read_config (void) /* {{{ */
-{
- oconfig_item_t *ci;
-
- ci = oconfig_parse_file (CONFIG_FILE);
- if (ci == NULL)
- return (-1);
-
- dispatch_config (ci);
-
- oconfig_free (ci);
-
- gl_config_submit ();
-
- return (0);
-} /* }}} int internal_read_config */
-
-static time_t get_config_mtime (void) /* {{{ */
-{
- struct stat statbuf;
- int status;
-
- memset (&statbuf, 0, sizeof (statbuf));
- status = stat (CONFIG_FILE, &statbuf);
- if (status != 0)
- return (0);
-
- return (statbuf.st_mtime);
-} /* }}} time_t get_config_mtime */
-
-int graph_read_config (void) /* {{{ */
-{
- time_t mtime;
-
- mtime = get_config_mtime ();
-
- if (mtime <= last_read_mtime)
- return (0);
-
- internal_read_config ();
-
- last_read_mtime = mtime;
-
- return (0);
-} /* }}} int graph_read_config */
-
-int graph_config_get_string (const oconfig_item_t *ci, /* {{{ */
- char **ret_str)
-{
- char *tmp;
-
- if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
- return (EINVAL);
-
- tmp = strdup (ci->values[0].value.string);
- if (tmp == NULL)
- return (ENOMEM);
-
- free (*ret_str);
- *ret_str = tmp;
-
- return (0);
-} /* }}} int graph_config_get_string */
-
-int graph_config_get_bool (const oconfig_item_t *ci, /* {{{ */
- _Bool *ret_bool)
-{
- if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
- return (EINVAL);
-
- if (ci->values[0].value.boolean)
- *ret_bool = 1;
- else
- *ret_bool = 0;
-
- return (0);
-} /* }}} int graph_config_get_bool */
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/graph_config.h b/graph_config.h
--- a/graph_config.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef GRAPH_CONFIG_H
-#define GRAPH_CONFIG_H 1
-
-#include "oconfig.h"
-
-int graph_read_config (void);
-
-int graph_config_get_string (const oconfig_item_t *ci, char **ret_str);
-int graph_config_get_bool (const oconfig_item_t *ci, _Bool *ret_bool);
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
-#endif /* GRAPH_CONFIG_H */
diff --git a/graph_def.c b/graph_def.c
--- a/graph_def.c
+++ /dev/null
@@ -1,348 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include "graph_def.h"
-#include "graph.h"
-#include "graph_config.h"
-#include "common.h"
-#include "oconfig.h"
-
-#include <fcgiapp.h>
-#include <fcgi_stdio.h>
-
-/*
- * Data structures
- */
-struct graph_def_s
-{
- graph_ident_t *select;
-
- char *ds_name;
- char *legend;
- uint32_t color;
- _Bool stack;
- _Bool area;
- char *format;
-
- graph_def_t *next;
-};
-
-/*
- * Private functions
- */
-#define DEF_CONFIG_FIELD(field) \
-static int def_config_##field (const oconfig_item_t *ci, graph_ident_t *ident) \
-{ \
- char *tmp = NULL; \
- int status = graph_config_get_string (ci, &tmp); \
- if (status != 0) \
- return (status); \
- ident_set_##field (ident, tmp); \
- free (tmp); \
- return (0); \
-} /* }}} int def_config_field */
-
-DEF_CONFIG_FIELD (host);
-DEF_CONFIG_FIELD (plugin);
-DEF_CONFIG_FIELD (plugin_instance);
-DEF_CONFIG_FIELD (type);
-DEF_CONFIG_FIELD (type_instance);
-
-#undef DEF_CONFIG_FIELD
-
-static int def_config_color (const oconfig_item_t *ci, uint32_t *ret_color) /* {{{ */
-{
- char *tmp;
- char *endptr;
- uint32_t color;
-
- if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
- return (EINVAL);
-
- tmp = ci->values[0].value.string;
-
- endptr = NULL;
- errno = 0;
- color = (uint32_t) strtoul (tmp, &endptr, /* base = */ 16);
- if ((errno != 0) || (endptr == tmp) || (color > 0x00ffffff))
- return (EINVAL);
-
- *ret_color = color;
-
- return (0);
-} /* }}} int def_config_color */
-
-static graph_def_t *def_config_get_obj (graph_config_t *cfg, /* {{{ */
- const oconfig_item_t *ci)
-{
- graph_ident_t *ident;
- char *ds_name = NULL;
- graph_def_t *def;
- int i;
-
- ident = graph_get_selector (cfg);
- if (ident == NULL)
- {
- fprintf (stderr, "def_config_get_obj: graph_get_selector failed");
- return (NULL);
- }
-
- for (i = 0; i < ci->children_num; i++)
- {
- oconfig_item_t *child;
-
-#define HANDLE_FIELD(name,field) \
- else if (strcasecmp (name, child->key) == 0) \
- def_config_##field (child, ident)
-
- child = ci->children + i;
- if (strcasecmp ("DSName", child->key) == 0)
- graph_config_get_string (child, &ds_name);
-
- HANDLE_FIELD ("Host", host);
- HANDLE_FIELD ("Plugin", plugin);
- HANDLE_FIELD ("PluginInstance", plugin_instance);
- HANDLE_FIELD ("Type", type);
- HANDLE_FIELD ("TypeInstance", type_instance);
-
-#undef HANDLE_FIELD
- }
-
- def = def_create (cfg, ident, ds_name);
- if (def == NULL)
- {
- fprintf (stderr, "def_config_get_obj: def_create failed\n");
- ident_destroy (ident);
- free (ds_name);
- return (NULL);
- }
-
- ident_destroy (ident);
- free (ds_name);
-
- return (def);
-} /* }}} graph_def_t *def_config_get_obj */
-
-/*
- * Public functions
- */
-graph_def_t *def_create (graph_config_t *cfg, graph_ident_t *ident, /* {{{ */
- const char *ds_name)
-{
- graph_ident_t *selector;
- graph_def_t *ret;
-
- if ((cfg == NULL) || (ident == NULL) || (ds_name == NULL))
- return (NULL);
-
- selector = graph_get_selector (cfg);
- if (selector == NULL)
- return (NULL);
-
- ret = malloc (sizeof (*ret));
- if (ret == NULL)
- {
- ident_destroy (selector);
- return (NULL);
- }
- memset (ret, 0, sizeof (*ret));
- ret->legend = NULL;
- ret->format = NULL;
-
- ret->ds_name = strdup (ds_name);
- if (ret->ds_name == NULL)
- {
- ident_destroy (selector);
- free (ret);
- return (NULL);
- }
-
- ret->color = get_random_color ();
- ret->next = NULL;
-
- ret->select = ident_copy_with_selector (selector, ident,
- IDENT_FLAG_REPLACE_ALL);
- if (ret->select == NULL)
- {
- ident_destroy (selector);
- free (ret->ds_name);
- free (ret);
- return (NULL);
- }
-
- ident_destroy (selector);
- return (ret);
-} /* }}} graph_def_t *def_create */
-
-void def_destroy (graph_def_t *def) /* {{{ */
-{
- graph_def_t *next;
-
- if (def == NULL)
- return;
-
- next = def->next;
-
- ident_destroy (def->select);
-
- free (def->ds_name);
- free (def->legend);
- free (def->format);
-
- free (def);
-
- def_destroy (next);
-} /* }}} void def_destroy */
-
-int def_config (graph_config_t *cfg, const oconfig_item_t *ci) /* {{{ */
-{
- graph_def_t *def;
- int i;
-
- def = def_config_get_obj (cfg, ci);
- if (def == NULL)
- return (EINVAL);
-
- for (i = 0; i < ci->children_num; i++)
- {
- oconfig_item_t *child;
-
- child = ci->children + i;
- if (strcasecmp ("Legend", child->key) == 0)
- graph_config_get_string (child, &def->legend);
- else if (strcasecmp ("Color", child->key) == 0)
- def_config_color (child, &def->color);
- else if (strcasecmp ("Stack", child->key) == 0)
- graph_config_get_bool (child, &def->stack);
- else if (strcasecmp ("Area", child->key) == 0)
- graph_config_get_bool (child, &def->area);
- else if (strcasecmp ("Format", child->key) == 0)
- graph_config_get_string (child, &def->format);
- else
- fprintf (stderr, "def_config: Ignoring unknown config option \"%s\"",
- child->key);
- }
-
- return (graph_add_def (cfg, def));
-} /* }}} int def_config */
-
-int def_append (graph_def_t *head, graph_def_t *def) /* {{{ */
-{
- graph_def_t *ptr;
-
- if ((head == NULL) || (def == NULL))
- return (EINVAL);
-
- ptr = head;
- while (ptr->next != NULL)
- ptr = ptr->next;
-
- ptr->next = def;
-
- return (0);
-} /* }}} int def_append */
-
-graph_def_t *def_search (graph_def_t *head, graph_ident_t *ident, /* {{{ */
- const char *ds_name)
-{
- graph_def_t *ptr;
-
- if ((head == NULL) || (ident == NULL) || (ds_name == NULL))
- return (NULL);
-
- for (ptr = head; ptr != NULL; ptr = ptr->next)
- {
- if (!ident_matches (ptr->select, ident))
- continue;
-
- if (strcmp (ptr->ds_name, ds_name) == 0)
- return (ptr);
- }
-
- return (NULL);
-} /* }}} graph_def_t *def_search */
-
-_Bool def_matches (graph_def_t *def, graph_ident_t *ident) /* {{{ */
-{
- return (ident_matches (def->select, ident));
-} /* }}} _Bool def_matches */
-
-int def_foreach (graph_def_t *def, def_callback_t callback, /* {{{ */
- void *user_data)
-{
- graph_def_t *ptr;
-
- if ((def == NULL) || (callback == NULL))
- return (EINVAL);
-
- for (ptr = def; ptr != NULL; ptr = ptr->next)
- {
- int status;
-
- status = (*callback) (ptr, user_data);
- if (status != 0)
- return (status);
- }
-
- return (0);
-} /* }}} int def_foreach */
-
-int def_get_rrdargs (graph_def_t *def, graph_ident_t *ident, /* {{{ */
- str_array_t *args)
-{
- char *file;
- int index;
-
- if ((def == NULL) || (ident == NULL) || (args == NULL))
- return (EINVAL);
-
- file = ident_to_file (ident);
- if (file == NULL)
- {
- DEBUG ("gl_ident_get_rrdargs: ident_to_file returned NULL.\n");
- return (-1);
- }
-
- DEBUG ("gl_ident_get_rrdargs: file = %s;\n", file);
-
- index = array_argc (args);
-
- /* CDEFs */
- array_append_format (args, "DEF:def_%04i_min=%s:%s:MIN",
- index, file, def->ds_name);
- array_append_format (args, "DEF:def_%04i_avg=%s:%s:AVERAGE",
- index, file, def->ds_name);
- array_append_format (args, "DEF:def_%04i_max=%s:%s:MAX",
- index, file, def->ds_name);
- /* VDEFs */
- array_append_format (args, "VDEF:vdef_%04i_min=def_%04i_min,MINIMUM",
- index, index);
- array_append_format (args, "VDEF:vdef_%04i_avg=def_%04i_avg,AVERAGE",
- index, index);
- array_append_format (args, "VDEF:vdef_%04i_max=def_%04i_max,MAXIMUM",
- index, index);
- array_append_format (args, "VDEF:vdef_%04i_lst=def_%04i_avg,LAST",
- index, index);
-
- /* Graph part */
- array_append_format (args, "%s:def_%04i_avg#%06"PRIx32":%s%s",
- def->area ? "AREA" : "LINE1",
- index, def->color,
- (def->legend != NULL) ? def->legend : def->ds_name,
- def->stack ? ":STACK" : "");
- array_append_format (args, "GPRINT:vdef_%04i_min:%s min,",
- index, (def->format != NULL) ? def->format : "%lg");
- array_append_format (args, "GPRINT:vdef_%04i_avg:%s avg,",
- index, (def->format != NULL) ? def->format : "%lg");
- array_append_format (args, "GPRINT:vdef_%04i_max:%s max,",
- index, (def->format != NULL) ? def->format : "%lg");
- array_append_format (args, "GPRINT:vdef_%04i_lst:%s last\\l",
- index, (def->format != NULL) ? def->format : "%lg");
-
- free (file);
-
- return (0);
-} /* }}} int def_get_rrdargs */
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/graph_def.h b/graph_def.h
--- a/graph_def.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef GRAPH_DEF_H
-#define GRAPH_DEF_H 1
-
-struct graph_def_s;
-typedef struct graph_def_s graph_def_t;
-
-typedef int (*def_callback_t) (graph_def_t *def,
- void *user_data);
-
-#include "graph.h"
-#include "graph_ident.h"
-#include "utils_array.h"
-#include "oconfig.h"
-
-graph_def_t *def_create (graph_config_t *cfg, graph_ident_t *ident,
- const char *ds_name);
-
-void def_destroy (graph_def_t *def);
-
-int def_config (graph_config_t *cfg, const oconfig_item_t *ci);
-
-int def_append (graph_def_t *head, graph_def_t *def);
-
-graph_def_t *def_search (graph_def_t *head, graph_ident_t *ident,
- const char *ds_name);
-
-_Bool def_matches (graph_def_t *def, graph_ident_t *ident);
-
-int def_foreach (graph_def_t *def, def_callback_t callback, void *user_data);
-
-int def_get_rrdargs (graph_def_t *def, graph_ident_t *ident,
- str_array_t *args);
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
-#endif
diff --git a/graph_ident.c b/graph_ident.c
--- a/graph_ident.c
+++ /dev/null
@@ -1,455 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <errno.h>
-#include <limits.h> /* PATH_MAX */
-
-#include "graph_ident.h"
-#include "common.h"
-#include "filesystem.h"
-
-/*
- * Data types
- */
-struct graph_ident_s /* {{{ */
-{
- char *host;
- char *plugin;
- char *plugin_instance;
- char *type;
- char *type_instance;
-}; /* }}} struct graph_ident_s */
-
-/*
- * Private functions
- */
-static char *part_copy_with_selector (const char *selector, /* {{{ */
- const char *part, unsigned int flags)
-{
- if ((selector == NULL) || (part == NULL))
- return (NULL);
-
- if ((flags & IDENT_FLAG_REPLACE_ANY) && IS_ANY (part))
- return (NULL);
-
- if ((flags & IDENT_FLAG_REPLACE_ALL) && IS_ALL (part))
- return (NULL);
-
- /* Replace the ANY and ALL flags if requested and if the selecter actually
- * *is* that flag. */
- if (IS_ANY (selector))
- {
- if (flags & IDENT_FLAG_REPLACE_ANY)
- return (strdup (part));
- else
- return (strdup (selector));
- }
-
- if (IS_ALL (selector))
- {
- if (flags & IDENT_FLAG_REPLACE_ALL)
- return (strdup (part));
- else
- return (strdup (selector));
- }
-
- if (strcmp (selector, part) != 0)
- return (NULL);
-
- /* Otherwise (no replacement), return a copy of the selector. */
- return (strdup (selector));
-} /* }}} char *part_copy_with_selector */
-
-static _Bool part_matches (const char *selector, /* {{{ */
- const char *part)
-{
- if ((selector == NULL) && (part == NULL))
- return (1);
-
- if (selector == NULL) /* && (part != NULL) */
- return (0);
-
- if (IS_ANY(selector) || IS_ALL(selector))
- return (1);
-
- if (part == NULL) /* && (selector != NULL) */
- return (0);
-
- if (strcmp (selector, part) == 0)
- return (1);
-
- return (0);
-} /* }}} _Bool part_matches */
-
-/*
- * Public functions
- */
-graph_ident_t *ident_create (const char *host, /* {{{ */
- const char *plugin, const char *plugin_instance,
- const char *type, const char *type_instance)
-{
- graph_ident_t *ret;
-
- if ((host == NULL)
- || (plugin == NULL) || (plugin_instance == NULL)
- || (type == NULL) || (type_instance == NULL))
- return (NULL);
-
- ret = malloc (sizeof (*ret));
- if (ret == NULL)
- return (NULL);
- memset (ret, 0, sizeof (*ret));
-
- ret->host = NULL;
- ret->host = NULL;
- ret->plugin = NULL;
- ret->plugin_instance = NULL;
- ret->type = NULL;
- ret->type_instance = NULL;
-
-#define COPY_PART(p) do { \
- ret->p = strdup (p); \
- if (ret->p == NULL) \
- { \
- free (ret->host); \
- free (ret->plugin); \
- free (ret->plugin_instance); \
- free (ret->type); \
- free (ret->type_instance); \
- free (ret); \
- return (NULL); \
- } \
-} while (0)
-
- COPY_PART(host);
- COPY_PART(plugin);
- COPY_PART(plugin_instance);
- COPY_PART(type);
- COPY_PART(type_instance);
-
-#undef COPY_PART
-
- return (ret);
-} /* }}} graph_ident_t *ident_create */
-
-graph_ident_t *ident_clone (const graph_ident_t *ident) /* {{{ */
-{
- return (ident_create (ident->host,
- ident->plugin, ident->plugin_instance,
- ident->type, ident->type_instance));
-} /* }}} graph_ident_t *ident_clone */
-
-graph_ident_t *ident_copy_with_selector (const graph_ident_t *selector, /* {{{ */
- const graph_ident_t *ident, unsigned int flags)
-{
- graph_ident_t *ret;
-
- if ((selector == NULL) || (ident == NULL))
- return (NULL);
-
- ret = malloc (sizeof (*ret));
- if (ret == NULL)
- return (NULL);
- memset (ret, 0, sizeof (*ret));
- ret->host = NULL;
- ret->plugin = NULL;
- ret->plugin_instance = NULL;
- ret->type = NULL;
- ret->type_instance = NULL;
-
-#define COPY_PART(p) do { \
- ret->p = part_copy_with_selector (selector->p, ident->p, flags); \
- if (ret->p == NULL) \
- { \
- free (ret->host); \
- free (ret->plugin); \
- free (ret->plugin_instance); \
- free (ret->type); \
- free (ret->type_instance); \
- return (NULL); \
- } \
-} while (0)
-
- COPY_PART (host);
- COPY_PART (plugin);
- COPY_PART (plugin_instance);
- COPY_PART (type);
- COPY_PART (type_instance);
-
-#undef COPY_PART
-
- return (ret);
-} /* }}} graph_ident_t *ident_copy_with_selector */
-
-void ident_destroy (graph_ident_t *ident) /* {{{ */
-{
- if (ident == NULL)
- return;
-
- free (ident->host);
- free (ident->plugin);
- free (ident->plugin_instance);
- free (ident->type);
- free (ident->type_instance);
-
- free (ident);
-} /* }}} void ident_destroy */
-
-/* ident_get_* methods {{{ */
-const char *ident_get_host (graph_ident_t *ident) /* {{{ */
-{
- if (ident == NULL)
- return (NULL);
-
- return (ident->host);
-} /* }}} char *ident_get_host */
-
-const char *ident_get_plugin (graph_ident_t *ident) /* {{{ */
-{
- if (ident == NULL)
- return (NULL);
-
- return (ident->plugin);
-} /* }}} char *ident_get_plugin */
-
-const char *ident_get_plugin_instance (graph_ident_t *ident) /* {{{ */
-{
- if (ident == NULL)
- return (NULL);
-
- return (ident->plugin_instance);
-} /* }}} char *ident_get_plugin_instance */
-
-const char *ident_get_type (graph_ident_t *ident) /* {{{ */
-{
- if (ident == NULL)
- return (NULL);
-
- return (ident->type);
-} /* }}} char *ident_get_type */
-
-const char *ident_get_type_instance (graph_ident_t *ident) /* {{{ */
-{
- if (ident == NULL)
- return (NULL);
-
- return (ident->type_instance);
-} /* }}} char *ident_get_type_instance */
-/* }}} ident_get_* methods */
-
-/* ident_set_* methods {{{ */
-int ident_set_host (graph_ident_t *ident, const char *host) /* {{{ */
-{
- char *tmp;
-
- if ((ident == NULL) || (host == NULL))
- return (EINVAL);
-
- tmp = strdup (host);
- if (tmp == NULL)
- return (ENOMEM);
-
- free (ident->host);
- ident->host = tmp;
-
- return (0);
-} /* }}} int ident_set_host */
-
-int ident_set_plugin (graph_ident_t *ident, const char *plugin) /* {{{ */
-{
- char *tmp;
-
- if ((ident == NULL) || (plugin == NULL))
- return (EINVAL);
-
- tmp = strdup (plugin);
- if (tmp == NULL)
- return (ENOMEM);
-
- free (ident->plugin);
- ident->plugin = tmp;
-
- return (0);
-} /* }}} int ident_set_plugin */
-
-int ident_set_plugin_instance (graph_ident_t *ident, const char *plugin_instance) /* {{{ */
-{
- char *tmp;
-
- if ((ident == NULL) || (plugin_instance == NULL))
- return (EINVAL);
-
- tmp = strdup (plugin_instance);
- if (tmp == NULL)
- return (ENOMEM);
-
- free (ident->plugin_instance);
- ident->plugin_instance = tmp;
-
- return (0);
-} /* }}} int ident_set_plugin_instance */
-
-int ident_set_type (graph_ident_t *ident, const char *type) /* {{{ */
-{
- char *tmp;
-
- if ((ident == NULL) || (type == NULL))
- return (EINVAL);
-
- tmp = strdup (type);
- if (tmp == NULL)
- return (ENOMEM);
-
- free (ident->type);
- ident->type = tmp;
-
- return (0);
-} /* }}} int ident_set_type */
-
-int ident_set_type_instance (graph_ident_t *ident, const char *type_instance) /* {{{ */
-{
- char *tmp;
-
- if ((ident == NULL) || (type_instance == NULL))
- return (EINVAL);
-
- tmp = strdup (type_instance);
- if (tmp == NULL)
- return (ENOMEM);
-
- free (ident->type_instance);
- ident->type_instance = tmp;
-
- return (0);
-} /* }}} int ident_set_type_instance */
-
-/* }}} ident_set_* methods */
-
-int ident_compare (const graph_ident_t *i0, /* {{{ */
- const graph_ident_t *i1)
-{
- int status;
-
-#define COMPARE_PART(p) do { \
- status = strcmp (i0->p, i1->p); \
- if (status != 0) \
- return (status); \
-} while (0)
-
- COMPARE_PART (host);
- COMPARE_PART (plugin);
- COMPARE_PART (plugin_instance);
- COMPARE_PART (type);
- COMPARE_PART (type_instance);
-
-#undef COMPARE_PART
-
- return (0);
-} /* }}} int ident_compare */
-
-_Bool ident_matches (const graph_ident_t *selector, /* {{{ */
- const graph_ident_t *ident)
-{
- if ((selector == NULL) && (ident == NULL))
- return (0);
- else if (selector == NULL)
- return (-1);
- else if (ident == NULL)
- return (1);
-
- if (!part_matches (selector->host, ident->host))
- return (0);
-
- if (!part_matches (selector->plugin, ident->plugin))
- return (0);
-
- if (!part_matches (selector->plugin_instance, ident->plugin_instance))
- return (0);
-
- if (!part_matches (selector->type, ident->type))
- return (0);
-
- if (!part_matches (selector->type_instance, ident->type_instance))
- return (0);
-
- return (1);
-} /* }}} _Bool ident_matches */
-
-char *ident_to_string (const graph_ident_t *ident) /* {{{ */
-{
- char buffer[PATH_MAX];
-
- buffer[0] = 0;
-
- strlcat (buffer, ident->host, sizeof (buffer));
- strlcat (buffer, "/", sizeof (buffer));
- strlcat (buffer, ident->plugin, sizeof (buffer));
- if (ident->plugin_instance[0] != 0)
- {
- strlcat (buffer, "-", sizeof (buffer));
- strlcat (buffer, ident->plugin_instance, sizeof (buffer));
- }
- strlcat (buffer, "/", sizeof (buffer));
- strlcat (buffer, ident->type, sizeof (buffer));
- if (ident->type_instance[0] != 0)
- {
- strlcat (buffer, "-", sizeof (buffer));
- strlcat (buffer, ident->type_instance, sizeof (buffer));
- }
-
- return (strdup (buffer));
-} /* }}} char *ident_to_string */
-
-char *ident_to_file (const graph_ident_t *ident) /* {{{ */
-{
- char buffer[PATH_MAX];
-
- buffer[0] = 0;
-
- strlcat (buffer, DATA_DIR, sizeof (buffer));
- strlcat (buffer, "/", sizeof (buffer));
-
- strlcat (buffer, ident->host, sizeof (buffer));
- strlcat (buffer, "/", sizeof (buffer));
- strlcat (buffer, ident->plugin, sizeof (buffer));
- if (ident->plugin_instance[0] != 0)
- {
- strlcat (buffer, "-", sizeof (buffer));
- strlcat (buffer, ident->plugin_instance, sizeof (buffer));
- }
- strlcat (buffer, "/", sizeof (buffer));
- strlcat (buffer, ident->type, sizeof (buffer));
- if (ident->type_instance[0] != 0)
- {
- strlcat (buffer, "-", sizeof (buffer));
- strlcat (buffer, ident->type_instance, sizeof (buffer));
- }
-
- strlcat (buffer, ".rrd", sizeof (buffer));
-
- return (strdup (buffer));
-} /* }}} char *ident_to_file */
-
-char *ident_to_json (const graph_ident_t *ident) /* {{{ */
-{
- char buffer[4096];
-
- buffer[0] = 0;
-
- strlcat (buffer, "{\"host\":\"", sizeof (buffer));
- strlcat (buffer, ident->host, sizeof (buffer));
- strlcat (buffer, "\",\"plugin\":\"", sizeof (buffer));
- strlcat (buffer, ident->plugin, sizeof (buffer));
- strlcat (buffer, "\",\"plugin_instance\":\"", sizeof (buffer));
- strlcat (buffer, ident->plugin_instance, sizeof (buffer));
- strlcat (buffer, "\",\"type\":\"", sizeof (buffer));
- strlcat (buffer, ident->type, sizeof (buffer));
- strlcat (buffer, "\",\"type_instance\":\"", sizeof (buffer));
- strlcat (buffer, ident->type_instance, sizeof (buffer));
- strlcat (buffer, "\"}", sizeof (buffer));
-
- return (strdup (buffer));
-} /* }}} char *ident_to_json */
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
-
diff --git a/graph_ident.h b/graph_ident.h
--- a/graph_ident.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef GRAPH_IDENT_H
-#define GRAPH_IDENT_H 1
-
-#define ANY_TOKEN "/any/"
-#define ALL_TOKEN "/all/"
-
-#define IS_ANY(str) (((str) != NULL) && (strcasecmp (ANY_TOKEN, (str)) == 0))
-#define IS_ALL(str) (((str) != NULL) && (strcasecmp (ALL_TOKEN, (str)) == 0))
-
-struct graph_ident_s;
-typedef struct graph_ident_s graph_ident_t;
-
-graph_ident_t *ident_create (const char *host,
- const char *plugin, const char *plugin_instance,
- const char *type, const char *type_instance);
-graph_ident_t *ident_clone (const graph_ident_t *ident);
-
-#define IDENT_FLAG_REPLACE_ALL 0x01
-#define IDENT_FLAG_REPLACE_ANY 0x02
-graph_ident_t *ident_copy_with_selector (const graph_ident_t *selector,
- const graph_ident_t *ident, unsigned int flags);
-
-void ident_destroy (graph_ident_t *ident);
-
-const char *ident_get_host (graph_ident_t *ident);
-const char *ident_get_plugin (graph_ident_t *ident);
-const char *ident_get_plugin_instance (graph_ident_t *ident);
-const char *ident_get_type (graph_ident_t *ident);
-const char *ident_get_type_instance (graph_ident_t *ident);
-
-int ident_set_host (graph_ident_t *ident, const char *host);
-int ident_set_plugin (graph_ident_t *ident, const char *plugin);
-int ident_set_plugin_instance (graph_ident_t *ident,
- const char *plugin_instance);
-int ident_set_type (graph_ident_t *ident, const char *type);
-int ident_set_type_instance (graph_ident_t *ident,
- const char *type_instance);
-
-int ident_compare (const graph_ident_t *i0,
- const graph_ident_t *i1);
-
-_Bool ident_matches (const graph_ident_t *selector,
- const graph_ident_t *ident);
-
-char *ident_to_string (const graph_ident_t *ident);
-char *ident_to_file (const graph_ident_t *ident);
-char *ident_to_json (const graph_ident_t *ident);
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
-#endif /* GRAPH_IDENT_H */
diff --git a/graph_instance.c b/graph_instance.c
--- a/graph_instance.c
+++ /dev/null
@@ -1,475 +0,0 @@
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include "graph_instance.h"
-#include "graph_ident.h"
-#include "graph_list.h"
-#include "common.h"
-#include "utils_params.h"
-
-#include <fcgiapp.h>
-#include <fcgi_stdio.h>
-
-struct graph_instance_s /* {{{ */
-{
- graph_ident_t *select;
-
- graph_ident_t **files;
- size_t files_num;
-
- graph_instance_t *next;
-}; /* }}} struct graph_instance_s */
-
-struct def_callback_data_s
-{
- graph_instance_t *inst;
- str_array_t *args;
-};
-typedef struct def_callback_data_s def_callback_data_t;
-
-/*
- * Private functions
- */
-/* Create one DEF for each data source in the file. Called by
- * "inst_get_default_defs" for each file. */
-static graph_def_t *ident_get_default_defs (graph_config_t *cfg, /* {{{ */
- graph_ident_t *ident, graph_def_t *def_head)
-{
- graph_def_t *defs = NULL;
- char *file;
- char **dses = NULL;
- size_t dses_num = 0;
- int status;
- size_t i;
-
- if ((cfg == NULL) || (ident == NULL))
- return (def_head);
-
- file = ident_to_file (ident);
- if (file == NULL)
- {
- fprintf (stderr, "ident_get_default_defs: ident_to_file failed\n");
- return (def_head);
- }
-
- status = ds_list_from_rrd_file (file, &dses_num, &dses);
- if (status != 0)
- {
- free (file);
- return (def_head);
- }
-
- for (i = 0; i < dses_num; i++)
- {
- graph_def_t *def;
-
- def = def_search (def_head, ident, dses[i]);
- if (def != NULL)
- continue;
-
- def = def_create (cfg, ident, dses[i]);
- if (def == NULL)
- continue;
-
- if (defs == NULL)
- defs = def;
- else
- def_append (defs, def);
-
- free (dses[i]);
- }
-
- free (dses);
- free (file);
-
- return (defs);
-} /* }}} int ident_get_default_defs */
-
-/* Create one or more DEFs for each file in the graph instance. The number
- * depends on the number of data sources in each of the files. Called from
- * "inst_get_rrdargs" if no DEFs are available from the configuration.
- * */
-static graph_def_t *inst_get_default_defs (graph_config_t *cfg, /* {{{ */
- graph_instance_t *inst)
-{
- graph_def_t *defs = NULL;
- size_t i;
-
- if ((cfg == NULL) || (inst == NULL))
- return (NULL);
-
- for (i = 0; i < inst->files_num; i++)
- {
- graph_def_t *def;
-
- def = ident_get_default_defs (cfg, inst->files[i], defs);
- if (def == NULL)
- continue;
-
- if (defs == NULL)
- defs = def;
- else
- def_append (defs, def);
- }
-
- return (defs);
-} /* }}} graph_def_t *inst_get_default_defs */
-
-/* Called with each DEF in turn. Calls "def_get_rrdargs" with every appropriate
- * file / DEF pair. */
-static int gl_instance_get_rrdargs_cb (graph_def_t *def, void *user_data) /* {{{ */
-{
- def_callback_data_t *data = user_data;
- graph_instance_t *inst = data->inst;
- str_array_t *args = data->args;
-
- size_t i;
-
- for (i = 0; i < inst->files_num; i++)
- {
- if (!def_matches (def, inst->files[i]))
- continue;
-
- def_get_rrdargs (def, inst->files[i], args);
- }
-
- return (0);
-} /* }}} int gl_instance_get_rrdargs_cb */
-
-static const char *get_part_from_param (const char *prim_key, /* {{{ */
- const char *sec_key)
-{
- const char *val;
-
- val = param (prim_key);
- if (val != NULL)
- return (val);
-
- return (param (sec_key));
-} /* }}} const char *get_part_from_param */
-
-/*
- * Public functions
- */
-graph_instance_t *inst_create (graph_config_t *cfg, /* {{{ */
- const graph_ident_t *ident)
-{
- graph_instance_t *i;
- graph_ident_t *selector;
-
- if ((cfg == NULL) || (ident == NULL))
- return (NULL);
-
- i = malloc (sizeof (*i));
- if (i == NULL)
- return (NULL);
- memset (i, 0, sizeof (*i));
-
- selector = graph_get_selector (cfg);
- if (selector == NULL)
- {
- fprintf (stderr, "inst_create: graph_get_selector failed\n");
- free (i);
- return (NULL);
- }
-
- i->select = ident_copy_with_selector (selector, ident,
- IDENT_FLAG_REPLACE_ANY);
- if (i->select == NULL)
- {
- fprintf (stderr, "inst_create: ident_copy_with_selector failed\n");
- ident_destroy (selector);
- free (i);
- return (NULL);
- }
-
- ident_destroy (selector);
-
- i->files = NULL;
- i->files_num = 0;
-
- i->next = NULL;
-
- return (i);
-} /* }}} graph_instance_t *inst_create */
-
-void inst_destroy (graph_instance_t *inst) /* {{{ */
-{
- graph_instance_t *next;
- size_t i;
-
- if (inst == NULL)
- return;
-
- next = inst->next;
-
- ident_destroy (inst->select);
-
- for (i = 0; i < inst->files_num; i++)
- ident_destroy (inst->files[i]);
- free (inst->files);
-
- free (inst);
-
- inst_destroy (next);
-} /* }}} void inst_destroy */
-
-int inst_add_file (graph_instance_t *inst, /* {{{ */
- const graph_ident_t *file)
-{
- graph_ident_t **tmp;
-
- tmp = realloc (inst->files, sizeof (*inst->files) * (inst->files_num + 1));
- if (tmp == NULL)
- return (ENOMEM);
- inst->files = tmp;
-
- inst->files[inst->files_num] = ident_clone (file);
- if (inst->files[inst->files_num] == NULL)
- return (ENOMEM);
-
- inst->files_num++;
-
- return (0);
-} /* }}} int inst_add_file */
-
-graph_instance_t *inst_get_selected (graph_config_t *cfg) /* {{{ */
-{
- const char *host = get_part_from_param ("inst_host", "host");
- const char *plugin = get_part_from_param ("inst_plugin", "plugin");
- const char *plugin_instance = get_part_from_param ("inst_plugin_instance", "plugin_instance");
- const char *type = get_part_from_param ("inst_type", "type");
- const char *type_instance = get_part_from_param ("inst_type_instance", "type_instance");
- graph_ident_t *ident;
- graph_instance_t *inst;
-
- if (cfg == NULL)
- cfg = gl_graph_get_selected ();
-
- if (cfg == NULL)
- {
- DEBUG ("inst_get_selected: cfg == NULL;\n");
- return (NULL);
- }
-
- if ((host == NULL)
- || (plugin == NULL) || (plugin_instance == NULL)
- || (type == NULL) || (type_instance == NULL))
- {
- DEBUG ("inst_get_selected: A parameter is NULL.\n");
- return (NULL);
- }
-
- ident = ident_create (host, plugin, plugin_instance, type, type_instance);
-
- for (inst = graph_get_instances (cfg); inst != NULL; inst = inst->next)
- {
- if (ident_compare (ident, inst->select) != 0)
- continue;
-
- ident_destroy (ident);
- return (inst);
- }
-
- DEBUG ("inst_get_selected: No match found.\n");
- ident_destroy (ident);
- return (NULL);
-} /* }}} graph_instance_t *inst_get_selected */
-
-int inst_get_rrdargs (graph_config_t *cfg, /* {{{ */
- graph_instance_t *inst,
- str_array_t *args)
-{
- def_callback_data_t data = { inst, args };
- graph_def_t *defs;
- int status;
-
- if ((cfg == NULL) || (inst == NULL) || (args == NULL))
- return (EINVAL);
-
- status = graph_get_rrdargs (cfg, inst, args);
- if (status != 0)
- return (status);
-
- defs = graph_get_defs (cfg);
- if (defs == NULL)
- {
- defs = inst_get_default_defs (cfg, inst);
-
- if (defs == NULL)
- return (-1);
-
- status = def_foreach (defs, gl_instance_get_rrdargs_cb, &data);
-
- def_destroy (defs);
- }
- else
- {
- status = def_foreach (defs, gl_instance_get_rrdargs_cb, &data);
- }
-
- return (status);
-} /* }}} int inst_get_rrdargs */
-
-graph_ident_t *inst_get_selector (graph_instance_t *inst) /* {{{ */
-{
- if (inst == NULL)
- return (NULL);
-
- return (ident_clone (inst->select));
-} /* }}} graph_ident_t *inst_get_selector */
-
-int inst_get_params (graph_config_t *cfg, graph_instance_t *inst, /* {{{ */
- char *buffer, size_t buffer_size)
-{
- graph_ident_t *cfg_select;
-
- if ((cfg == NULL) || (inst == NULL)
- || (buffer == NULL) || (buffer_size < 1))
- return (EINVAL);
-
- cfg_select = graph_get_selector (cfg);
- if (cfg_select == NULL)
- {
- fprintf (stderr, "inst_get_params: graph_get_selector failed");
- return (-1);
- }
-
- buffer[0] = 0;
-
-#define COPY_FIELD(field) do { \
- const char *cfg_f = ident_get_##field (cfg_select); \
- const char *inst_f = ident_get_##field (inst->select); \
- if (strcmp (cfg_f, inst_f) == 0) \
- { \
- strlcat (buffer, #field, buffer_size); \
- strlcat (buffer, "=", buffer_size); \
- strlcat (buffer, cfg_f, buffer_size); \
- } \
- else \
- { \
- strlcat (buffer, "graph_", buffer_size); \
- strlcat (buffer, #field, buffer_size); \
- strlcat (buffer, "=", buffer_size); \
- strlcat (buffer, cfg_f, buffer_size); \
- strlcat (buffer, ";", buffer_size); \
- strlcat (buffer, "inst_", buffer_size); \
- strlcat (buffer, #field, buffer_size); \
- strlcat (buffer, "=", buffer_size); \
- strlcat (buffer, inst_f, buffer_size); \
- } \
-} while (0)
-
- COPY_FIELD(host);
- strlcat (buffer, ";", buffer_size);
- COPY_FIELD(plugin);
- strlcat (buffer, ";", buffer_size);
- COPY_FIELD(plugin_instance);
- strlcat (buffer, ";", buffer_size);
- COPY_FIELD(type);
- strlcat (buffer, ";", buffer_size);
- COPY_FIELD(type_instance);
-
-#undef COPY_FIELD
-
- ident_destroy (cfg_select);
-
- return (0);
-} /* }}} int inst_get_params */
-
-int inst_append (graph_instance_t *head, graph_instance_t *inst) /* {{{ */
-{
- graph_instance_t *ptr;
-
- if ((head == NULL) || (inst == NULL))
- return (EINVAL);
-
- ptr = head;
- while (ptr->next != NULL)
- ptr = ptr->next;
-
- ptr->next = inst;
-
- return (0);
-} /* }}} int inst_append */
-
-int inst_foreach (graph_instance_t *inst, /* {{{ */
- inst_callback_t cb, void *user_data)
-{
- graph_instance_t *ptr;
-
- if ((inst == NULL) || (cb == NULL))
- return (EINVAL);
-
- for (ptr = inst; ptr != NULL; ptr = ptr->next)
- {
- int status;
-
- status = (*cb) (ptr, user_data);
- if (status != 0)
- return (status);
- }
-
- return (0);
-} /* }}} int inst_foreach */
-
-graph_instance_t *inst_find_matching (graph_instance_t *inst, /* {{{ */
- const graph_ident_t *ident)
-{
- graph_instance_t *ptr;
-
- if ((inst == NULL) || (ident == NULL))
- return (NULL);
-
- for (ptr = inst; ptr != NULL; ptr = ptr->next)
- if (ident_matches (ptr->select, ident))
- return (ptr);
-
- return (NULL);
-} /* }}} graph_instance_t *inst_find_matching */
-
-int inst_describe (graph_config_t *cfg, graph_instance_t *inst, /* {{{ */
- char *buffer, size_t buffer_size)
-{
- graph_ident_t *cfg_select;
-
- if ((cfg == NULL) || (inst == NULL)
- || (buffer == NULL) || (buffer_size < 2))
- return (EINVAL);
-
- cfg_select = graph_get_selector (cfg);
- if (cfg_select == NULL)
- {
- fprintf (stderr, "inst_describe: graph_get_selector failed\n");
- return (-1);
- }
-
- buffer[0] = 0;
-
-#define CHECK_FIELD(field) do { \
- if (IS_ANY (ident_get_##field (cfg_select))) \
- { \
- if (buffer[0] != 0) \
- strlcat (buffer, "/", buffer_size); \
- strlcat (buffer, ident_get_##field (inst->select), buffer_size); \
- } \
-} while (0)
-
- CHECK_FIELD (host);
- CHECK_FIELD (plugin);
- CHECK_FIELD (plugin_instance);
- CHECK_FIELD (type);
- CHECK_FIELD (type_instance);
-
-#undef CHECK_FIELD
-
- if (buffer[0] == 0)
- strlcat (buffer, "default", buffer_size);
-
- ident_destroy (cfg_select);
-
- return (0);
-} /* }}} int inst_describe */
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/graph_instance.h b/graph_instance.h
--- a/graph_instance.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef GRAPH_INSTANCE_H
-#define GRAPH_INSTANCE_H 1
-
-/*
- * Data types
- */
-struct graph_instance_s;
-typedef struct graph_instance_s graph_instance_t;
-
-typedef int (*inst_callback_t) (graph_instance_t *inst, void *user_data);
-
-#include "graph.h"
-#include "utils_array.h"
-
-/*
- * Callback types
- */
-/*
- * Methods
- */
-graph_instance_t *inst_create (graph_config_t *cfg,
- const graph_ident_t *ident);
-
-void inst_destroy (graph_instance_t *inst);
-
-int inst_add_file (graph_instance_t *inst, const graph_ident_t *file);
-
-graph_instance_t *inst_get_selected (graph_config_t *cfg);
-
-int inst_get_params (graph_config_t *cfg, graph_instance_t *inst,
- char *buffer, size_t buffer_size);
-
-int inst_get_rrdargs (graph_config_t *cfg, graph_instance_t *inst,
- str_array_t *args);
-
-graph_ident_t *inst_get_selector (graph_instance_t *inst);
-
-int inst_append (graph_instance_t *head, graph_instance_t *inst);
-
-int inst_foreach (graph_instance_t *inst,
- inst_callback_t cb, void *user_data);
-
-graph_instance_t *inst_find_matching (graph_instance_t *inst,
- const graph_ident_t *ident);
-
-int inst_describe (graph_config_t *cfg, graph_instance_t *inst,
- char *buffer, size_t buffer_size);
-
-#endif /* GRAPH_INSTANCE_H */
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/graph_list.c b/graph_list.c
--- a/graph_list.c
+++ /dev/null
@@ -1,287 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <string.h>
-#include <time.h>
-#include <errno.h>
-
-#include "graph_list.h"
-#include "graph_ident.h"
-#include "graph_def.h"
-#include "graph_config.h"
-#include "common.h"
-#include "filesystem.h"
-#include "utils_params.h"
-
-#include <fcgiapp.h>
-#include <fcgi_stdio.h>
-
-/*
- * Defines
- */
-#define UPDATE_INTERVAL 10
-
-/*
- * Global variables
- */
-static graph_config_t **gl_active = NULL;
-static size_t gl_active_num = 0;
-
-static graph_config_t **gl_staging = NULL;
-static size_t gl_staging_num = 0;
-
-static time_t gl_last_update = 0;
-
-/*
- * Private functions
- */
-int gl_add_graph_internal (graph_config_t *cfg, /* {{{ */
- graph_config_t ***gl_array, size_t *gl_array_num)
-{
- graph_config_t **tmp;
-
-#define ARRAY_PTR (*gl_array)
-#define ARRAY_SIZE (*gl_array_num)
-
- if (cfg == NULL)
- return (EINVAL);
-
- tmp = realloc (ARRAY_PTR, sizeof (*ARRAY_PTR) * (ARRAY_SIZE + 1));
- if (tmp == NULL)
- return (ENOMEM);
- ARRAY_PTR = tmp;
-
- ARRAY_PTR[ARRAY_SIZE] = cfg;
- ARRAY_SIZE++;
-
-#undef ARRAY_SIZE
-#undef ARRAY_PTR
-
- return (0);
-} /* }}} int gl_add_graph_internal */
-
-static int gl_register_file (const graph_ident_t *file, /* {{{ */
- __attribute__((unused)) void *user_data)
-{
- graph_config_t *cfg;
- int num_graphs = 0;
- size_t i;
-
- for (i = 0; i < gl_active_num; i++)
- {
- graph_config_t *cfg = gl_active[i];
- int status;
-
- if (!graph_matches (cfg, file))
- continue;
-
- status = graph_add_file (cfg, file);
- if (status != 0)
- {
- /* report error */;
- }
- else
- {
- num_graphs++;
- }
- }
-
- if (num_graphs == 0)
- {
- cfg = graph_create (file);
- gl_add_graph_internal (cfg, &gl_active, &gl_active_num);
- graph_add_file (cfg, file);
- }
-
- return (0);
-} /* }}} int gl_register_file */
-
-static const char *get_part_from_param (const char *prim_key, /* {{{ */
- const char *sec_key)
-{
- const char *val;
-
- val = param (prim_key);
- if (val != NULL)
- return (val);
-
- return (param (sec_key));
-} /* }}} const char *get_part_from_param */
-
-static int gl_clear_instances (void) /* {{{ */
-{
- size_t i;
-
- for (i = 0; i < gl_active_num; i++)
- graph_clear_instances (gl_active[i]);
-
- return (0);
-} /* }}} int gl_clear_instances */
-
-
-/*
- * Global functions
- */
-int gl_add_graph (graph_config_t *cfg) /* {{{ */
-{
- return (gl_add_graph_internal (cfg, &gl_staging, &gl_staging_num));
-} /* }}} int gl_add_graph */
-
-int gl_config_submit (void) /* {{{ */
-{
- graph_config_t **old;
- size_t old_num;
- size_t i;
-
- old = gl_active;
- old_num = gl_active_num;
-
- gl_active = gl_staging;
- gl_active_num = gl_staging_num;
-
- gl_staging = NULL;
- gl_staging_num = 0;
-
- for (i = 0; i < old_num; i++)
- {
- graph_destroy (old[i]);
- old[i] = NULL;
- }
- free (old);
-
- return (0);
-} /* }}} int graph_config_submit */
-
-int gl_graph_get_all (gl_cfg_callback callback, /* {{{ */
- void *user_data)
-{
- size_t i;
-
- if (callback == NULL)
- return (EINVAL);
-
- gl_update ();
-
- for (i = 0; i < gl_active_num; i++)
- {
- int status;
-
- status = (*callback) (gl_active[i], user_data);
- if (status != 0)
- return (status);
- }
-
- return (0);
-} /* }}} int gl_graph_get_all */
-
-graph_config_t *gl_graph_get_selected (void) /* {{{ */
-{
- const char *host = get_part_from_param ("graph_host", "host");
- const char *plugin = get_part_from_param ("graph_plugin", "plugin");
- const char *plugin_instance = get_part_from_param ("graph_plugin_instance", "plugin_instance");
- const char *type = get_part_from_param ("graph_type", "type");
- const char *type_instance = get_part_from_param ("graph_type_instance", "type_instance");
- graph_ident_t *ident;
- size_t i;
-
- if ((host == NULL)
- || (plugin == NULL) || (plugin_instance == NULL)
- || (type == NULL) || (type_instance == NULL))
- return (NULL);
-
- ident = ident_create (host, plugin, plugin_instance, type, type_instance);
-
- gl_update ();
-
- for (i = 0; i < gl_active_num; i++)
- {
- if (graph_compare (gl_active[i], ident) != 0)
- continue;
-
- ident_destroy (ident);
- return (gl_active[i]);
- }
-
- ident_destroy (ident);
- return (NULL);
-} /* }}} graph_config_t *gl_graph_get_selected */
-
-/* gl_instance_get_all, gl_graph_instance_get_all {{{ */
-struct gl_inst_callback_data /* {{{ */
-{
- graph_config_t *cfg;
- gl_inst_callback callback;
- void *user_data;
-}; /* }}} struct gl_inst_callback_data */
-
-static int gl_inst_callback_handler (graph_instance_t *inst, /* {{{ */
- void *user_data)
-{
- struct gl_inst_callback_data *data = user_data;
-
- return ((*data->callback) (data->cfg, inst, data->user_data));
-} /* }}} int gl_inst_callback_handler */
-
-int gl_graph_instance_get_all (graph_config_t *cfg, /* {{{ */
- gl_inst_callback callback, void *user_data)
-{
- struct gl_inst_callback_data data =
- {
- cfg,
- callback,
- user_data
- };
-
- if ((cfg == NULL) || (callback == NULL))
- return (EINVAL);
-
- return (inst_foreach (graph_get_instances (cfg),
- gl_inst_callback_handler, &data));
-} /* }}} int gl_graph_instance_get_all */
-
-int gl_instance_get_all (gl_inst_callback callback, /* {{{ */
- void *user_data)
-{
- size_t i;
-
- gl_update ();
-
- for (i = 0; i < gl_active_num; i++)
- {
- int status;
-
- status = gl_graph_instance_get_all (gl_active[i], callback, user_data);
- if (status != 0)
- return (status);
- }
-
- return (0);
-} /* }}} int gl_instance_get_all */
-/* }}} gl_instance_get_all, gl_graph_instance_get_all */
-
-int gl_update (void) /* {{{ */
-{
- time_t now;
- int status;
-
- /*
- printf ("Content-Type: text/plain\n\n");
- */
-
- now = time (NULL);
-
- if ((gl_last_update + UPDATE_INTERVAL) >= now)
- return (0);
-
- graph_read_config ();
-
- gl_clear_instances ();
- status = fs_scan (/* callback = */ gl_register_file, /* user data = */ NULL);
-
- gl_last_update = now;
-
- return (status);
-} /* }}} int gl_update */
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/graph_list.h b/graph_list.h
--- a/graph_list.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef GRAPH_LIST_H
-#define GRAPH_LIST_H 1
-
-#include "graph_instance.h"
-
-/*
- * Callback types
- */
-typedef int (*gl_cfg_callback) (graph_config_t *cfg,
- void *user_data);
-
-typedef int (*gl_inst_callback) (graph_config_t *cfg,
- graph_instance_t *inst, void *user_data);
-
-/*
- * Functions
- */
-int gl_add_graph (graph_config_t *cfg);
-
-int gl_config_submit (void);
-
-int gl_graph_get_all (gl_cfg_callback callback,
- void *user_data);
-
-graph_config_t *gl_graph_get_selected (void);
-
-int gl_graph_instance_get_all (graph_config_t *cfg,
- gl_inst_callback callback, void *user_data);
-
-int gl_instance_get_all (gl_inst_callback callback,
- void *user_data);
-
-int gl_update (void);
-
-#endif /* GRAPH_LIST_H */
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/oconfig.c b/oconfig.c
--- a/oconfig.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/**
- * oconfig - src/oconfig.c
- * Copyright (C) 2006,2007 Florian octo Forster <octo at verplant.org>
- *
- * 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; only version 2 of the License is applicable.
- *
- * 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.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-
-#include "oconfig.h"
-
-extern FILE *yyin;
-
-oconfig_item_t *ci_root;
-const char *c_file;
-
-static void yyset_in (FILE *fd)
-{
- yyin = fd;
-} /* void yyset_in */
-
-oconfig_item_t *oconfig_parse_fh (FILE *fh)
-{
- int status;
- oconfig_item_t *ret;
-
- char file[10];
-
- yyset_in (fh);
-
- if (NULL == c_file) {
- int status;
-
- status = snprintf (file, sizeof (file), "<fd#%d>", fileno (fh));
-
- if ((status < 0) || (((size_t) status) >= sizeof (file))) {
- c_file = "<unknown>";
- }
- else {
- file[sizeof (file) - 1] = '\0';
- c_file = file;
- }
- }
-
- status = yyparse ();
- if (status != 0)
- {
- fprintf (stderr, "yyparse returned error #%i\n", status);
- return (NULL);
- }
-
- c_file = NULL;
-
- ret = ci_root;
- ci_root = NULL;
- yyset_in ((FILE *) 0);
-
- return (ret);
-} /* oconfig_item_t *oconfig_parse_fh */
-
-oconfig_item_t *oconfig_parse_file (const char *file)
-{
- FILE *fh;
- oconfig_item_t *ret;
-
- c_file = file;
-
- fh = fopen (file, "r");
- if (fh == NULL)
- {
- fprintf (stderr, "fopen (%s) failed: %s\n", file, strerror (errno));
- return (NULL);
- }
-
- ret = oconfig_parse_fh (fh);
- fclose (fh);
-
- c_file = NULL;
-
- return (ret);
-} /* oconfig_item_t *oconfig_parse_file */
-
-oconfig_item_t *oconfig_clone (const oconfig_item_t *ci_orig)
-{
- oconfig_item_t *ci_copy;
-
- ci_copy = (oconfig_item_t *) malloc (sizeof (*ci_copy));
- if (ci_copy == NULL)
- {
- fprintf (stderr, "malloc failed.\n");
- return (NULL);
- }
- memset (ci_copy, 0, sizeof (*ci_copy));
- ci_copy->values = NULL;
- ci_copy->parent = NULL;
- ci_copy->children = NULL;
-
- ci_copy->key = strdup (ci_orig->key);
- if (ci_copy->key == NULL)
- {
- fprintf (stderr, "strdup failed.\n");
- free (ci_copy);
- return (NULL);
- }
-
- if (ci_orig->values_num > 0) /* {{{ */
- {
- int i;
-
- ci_copy->values = (oconfig_value_t *) calloc (ci_orig->values_num,
- sizeof (*ci_copy->values));
- if (ci_copy->values == NULL)
- {
- fprintf (stderr, "calloc failed.\n");
- free (ci_copy->key);
- free (ci_copy);
- return (NULL);
- }
- ci_copy->values_num = ci_orig->values_num;
-
- for (i = 0; i < ci_copy->values_num; i++)
- {
- ci_copy->values[i].type = ci_orig->values[i].type;
- if (ci_copy->values[i].type == OCONFIG_TYPE_STRING)
- {
- ci_copy->values[i].value.string
- = strdup (ci_orig->values[i].value.string);
- if (ci_copy->values[i].value.string == NULL)
- {
- fprintf (stderr, "strdup failed.\n");
- oconfig_free (ci_copy);
- return (NULL);
- }
- }
- else /* ci_copy->values[i].type != OCONFIG_TYPE_STRING) */
- {
- ci_copy->values[i].value = ci_orig->values[i].value;
- }
- }
- } /* }}} if (ci_orig->values_num > 0) */
-
- if (ci_orig->children_num > 0) /* {{{ */
- {
- int i;
-
- ci_copy->children = (oconfig_item_t *) calloc (ci_orig->children_num,
- sizeof (*ci_copy->children));
- if (ci_copy->children == NULL)
- {
- fprintf (stderr, "calloc failed.\n");
- oconfig_free (ci_copy);
- return (NULL);
- }
- ci_copy->children_num = ci_orig->children_num;
-
- for (i = 0; i < ci_copy->children_num; i++)
- {
- oconfig_item_t *child;
-
- child = oconfig_clone (ci_orig->children + i);
- if (child == NULL)
- {
- oconfig_free (ci_copy);
- return (NULL);
- }
- child->parent = ci_copy;
- ci_copy->children[i] = *child;
- free (child);
- } /* for (i = 0; i < ci_copy->children_num; i++) */
- } /* }}} if (ci_orig->children_num > 0) */
-
- return (ci_copy);
-} /* oconfig_item_t *oconfig_clone */
-
-void oconfig_free (oconfig_item_t *ci)
-{
- int i;
-
- if (ci == NULL)
- return;
-
- if (ci->key != NULL)
- free (ci->key);
-
- for (i = 0; i < ci->values_num; i++)
- if ((ci->values[i].type == OCONFIG_TYPE_STRING)
- && (NULL != ci->values[i].value.string))
- free (ci->values[i].value.string);
-
- if (ci->values != NULL)
- free (ci->values);
-
- for (i = 0; i < ci->children_num; i++)
- oconfig_free (ci->children + i);
-
- if (ci->children != NULL)
- free (ci->children);
-}
-
-/*
- * vim:shiftwidth=2:tabstop=8:softtabstop=2:fdm=marker
- */
diff --git a/oconfig.h b/oconfig.h
--- a/oconfig.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef OCONFIG_H
-#define OCONFIG_H 1
-
-#include <stdio.h>
-
-/**
- * oconfig - src/oconfig.h
- * Copyright (C) 2006-2009 Florian octo Forster <octo at verplant.org>
- *
- * 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; only version 2 of the License is applicable.
- *
- * 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.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- * Types
- */
-#define OCONFIG_TYPE_STRING 0
-#define OCONFIG_TYPE_NUMBER 1
-#define OCONFIG_TYPE_BOOLEAN 2
-
-struct oconfig_value_s
-{
- union
- {
- char *string;
- double number;
- int boolean;
- } value;
- int type;
-};
-typedef struct oconfig_value_s oconfig_value_t;
-
-struct oconfig_item_s;
-typedef struct oconfig_item_s oconfig_item_t;
-struct oconfig_item_s
-{
- char *key;
- oconfig_value_t *values;
- int values_num;
-
- oconfig_item_t *parent;
- oconfig_item_t *children;
- int children_num;
-};
-
-/*
- * Functions
- */
-oconfig_item_t *oconfig_parse_fh (FILE *fh);
-oconfig_item_t *oconfig_parse_file (const char *file);
-
-oconfig_item_t *oconfig_clone (const oconfig_item_t *ci);
-
-void oconfig_free (oconfig_item_t *ci);
-
-/*
- * vim: shiftwidth=2:tabstop=8:softtabstop=2
- */
-#endif /* OCONFIG_H */
diff --git a/parser.y b/parser.y
--- a/parser.y
+++ /dev/null
@@ -1,239 +0,0 @@
-/**
- * oconfig - src/parser.y
- * Copyright (C) 2007,2008 Florian octo Forster <octo at verplant.org>
- *
- * 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; only version 2 of the License is applicable.
- *
- * 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.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-%{
-#include <stdlib.h>
-#include <string.h>
-#include "oconfig.h"
-#include "aux_types.h"
-
-static char *unquote (const char *orig);
-static int yyerror (const char *s);
-
-/* Lexer variables */
-extern int yylineno;
-extern char *yytext;
-
-extern oconfig_item_t *ci_root;
-extern char *c_file;
-%}
-
-%start entire_file
-
-%union {
- double number;
- int boolean;
- char *string;
- oconfig_value_t cv;
- oconfig_item_t ci;
- argument_list_t al;
- statement_list_t sl;
-}
-
-%token <number> NUMBER
-%token <boolean> BTRUE BFALSE
-%token <string> QUOTED_STRING UNQUOTED_STRING
-%token SLASH OPENBRAC CLOSEBRAC EOL
-
-%type <string> string
-%type <string> identifier
-/* arguments */
-%type <cv> argument
-%type <al> argument_list
-/* blocks */
-%type <ci> block_begin
-%type <ci> block
-%type <string> block_end
-/* statements */
-%type <ci> option
-%type <ci> statement
-%type <sl> statement_list
-%type <ci> entire_file
-
-/* pass an verbose, specific error message to yyerror() */
-%error-verbose
-
-%%
-string:
- QUOTED_STRING {$$ = unquote ($1);}
- | UNQUOTED_STRING {$$ = strdup ($1);}
- ;
-
-argument:
- NUMBER {$$.value.number = $1; $$.type = OCONFIG_TYPE_NUMBER;}
- | BTRUE {$$.value.boolean = 1; $$.type = OCONFIG_TYPE_BOOLEAN;}
- | BFALSE {$$.value.boolean = 0; $$.type = OCONFIG_TYPE_BOOLEAN;}
- | string {$$.value.string = $1; $$.type = OCONFIG_TYPE_STRING;}
- ;
-
-argument_list:
- argument_list argument
- {
- $$ = $1;
- $$.argument_num++;
- $$.argument = realloc ($$.argument, $$.argument_num * sizeof (oconfig_value_t));
- $$.argument[$$.argument_num-1] = $2;
- }
- | argument
- {
- $$.argument = malloc (sizeof (oconfig_value_t));
- $$.argument[0] = $1;
- $$.argument_num = 1;
- }
- ;
-
-identifier:
- UNQUOTED_STRING {$$ = strdup ($1);}
- ;
-
-option:
- identifier argument_list EOL
- {
- memset (&$$, '\0', sizeof ($$));
- $$.key = $1;
- $$.values = $2.argument;
- $$.values_num = $2.argument_num;
- }
- ;
-
-block_begin:
- OPENBRAC identifier CLOSEBRAC EOL
- {
- memset (&$$, '\0', sizeof ($$));
- $$.key = $2;
- }
- |
- OPENBRAC identifier argument_list CLOSEBRAC EOL
- {
- memset (&$$, '\0', sizeof ($$));
- $$.key = $2;
- $$.values = $3.argument;
- $$.values_num = $3.argument_num;
- }
- ;
-
-block_end:
- OPENBRAC SLASH identifier CLOSEBRAC EOL
- {
- $$ = $3;
- }
- ;
-
-block:
- block_begin statement_list block_end
- {
- if (strcmp ($1.key, $3) != 0)
- {
- printf ("block_begin = %s; block_end = %s;\n", $1.key, $3);
- yyerror ("Block not closed..\n");
- exit (1);
- }
- free ($3); $3 = NULL;
- $$ = $1;
- $$.children = $2.statement;
- $$.children_num = $2.statement_num;
- }
- ;
-
-statement:
- option {$$ = $1;}
- | block {$$ = $1;}
- | EOL {$$.values_num = 0;}
- ;
-
-statement_list:
- statement_list statement
- {
- $$ = $1;
- if (($2.values_num > 0) || ($2.children_num > 0))
- {
- $$.statement_num++;
- $$.statement = realloc ($$.statement, $$.statement_num * sizeof (oconfig_item_t));
- $$.statement[$$.statement_num-1] = $2;
- }
- }
- | statement
- {
- if (($1.values_num > 0) || ($1.children_num > 0))
- {
- $$.statement = malloc (sizeof (oconfig_item_t));
- $$.statement[0] = $1;
- $$.statement_num = 1;
- }
- else
- {
- $$.statement = NULL;
- $$.statement_num = 0;
- }
- }
- ;
-
-entire_file:
- statement_list
- {
- ci_root = malloc (sizeof (oconfig_item_t));
- memset (ci_root, '\0', sizeof (oconfig_item_t));
- ci_root->children = $1.statement;
- ci_root->children_num = $1.statement_num;
- }
- ;
-
-%%
-static int yyerror (const char *s)
-{
- char *text;
-
- if (*yytext == '\n')
- text = "<newline>";
- else
- text = yytext;
-
- fprintf (stderr, "Parse error in file `%s', line %i near `%s': %s\n",
- c_file, yylineno, text, s);
- return (-1);
-} /* int yyerror */
-
-static char *unquote (const char *orig)
-{
- char *ret = strdup (orig);
- int len;
- int i;
-
- if (ret == NULL)
- return (NULL);
-
- len = strlen (ret);
-
- if ((len < 2) || (ret[0] != '"') || (ret[len - 1] != '"'))
- return (ret);
-
- len -= 2;
- memmove (ret, ret + 1, len);
- ret[len] = '\0';
-
- for (i = 0; i < len; i++)
- {
- if (ret[i] == '\\')
- {
- memmove (ret + i, ret + (i + 1), len - i);
- len--;
- }
- }
-
- return (ret);
-} /* char *unquote */
diff --git a/scanner.l b/scanner.l
--- a/scanner.l
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- * oconfig - src/scanner.l
- * Copyright (C) 2007 Florian octo Forster <octo at verplant.org>
- * Copyright (C) 2008 Sebastian tokkee Harl <sh at tokkee.org>
- *
- * 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; only version 2 of the License is applicable.
- *
- * 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.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-%{
-#include <stdlib.h>
-#include "oconfig.h"
-#include "aux_types.h"
-#include "parser.h"
-
-/* multiline string buffer */
-static char *ml_buffer = NULL;
-static int ml_pos = 0;
-static int ml_len = 0;
-
-#define ml_free (ml_len - ml_pos)
-
-static void ml_append (char *);
-
-#ifdef yyterminate
-# undef yyterminate
-#endif
-#define yyterminate() \
- do { free (ml_buffer); ml_buffer = NULL; ml_pos = 0; ml_len = 0; \
- return YY_NULL; } while (0)
-%}
-%option yylineno
-%option noyywrap
-%x ML
-WHITE_SPACE [\ \t\b]
-NON_WHITE_SPACE [^\ \t\b]
-EOL (\r\n|\n)
-QUOTED_STRING ([^\\"]+|\\.)*
-UNQUOTED_STRING [0-9A-Za-z_]+
-HEX_NUMBER 0[xX][0-9a-fA-F]+
-OCT_NUMBER 0[0-7]+
-DEC_NUMBER [\+\-]?[0-9]+
-FLOAT_NUMBER [\+\-]?[0-9]*\.[0-9]+([eE][\+\-][0-9]+)?
-NUMBER ({FLOAT_NUMBER}|{HEX_NUMBER}|{OCT_NUMBER}|{DEC_NUMBER})
-BOOL_TRUE (true|yes|on)
-BOOL_FALSE (false|no|off)
-COMMENT #.*
-PORT (6(5(5(3[0-5]|[0-2][0-9])|[0-4][0-9][0-9])|[0-4][0-9][0-9][0-9])|[1-5][0-9][0-9][0-9][0-9]|[1-9][0-9]?[0-9]?[0-9]?)
-IP_BYTE (2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])
-IPV4_ADDR {IP_BYTE}\.{IP_BYTE}\.{IP_BYTE}\.{IP_BYTE}(:{PORT})?
-
-%%
-{WHITE_SPACE} |
-{COMMENT} {/* ignore */}
-
-\\{EOL} {/* continue line */}
-
-{EOL} {return (EOL);}
-"/" {return (SLASH);}
-"<" {return (OPENBRAC);}
-">" {return (CLOSEBRAC);}
-{BOOL_TRUE} {yylval.boolean = 1; return (BTRUE);}
-{BOOL_FALSE} {yylval.boolean = 0; return (BFALSE);}
-
-{IPV4_ADDR} {yylval.string = yytext; return (UNQUOTED_STRING);}
-
-{NUMBER} {yylval.number = strtod (yytext, NULL); return (NUMBER);}
-
-\"{QUOTED_STRING}\" {yylval.string = yytext; return (QUOTED_STRING);}
-{UNQUOTED_STRING} {yylval.string = yytext; return (UNQUOTED_STRING);}
-
-\"{QUOTED_STRING}\\{EOL} {
- int len = strlen (yytext);
-
- ml_pos = 0;
-
- /* remove "\\<EOL>" */
- if ('\r' == yytext[len - 2])
- len -= 3;
- else
- len -= 2;
- yytext[len] = '\0';
-
- ml_append (yytext);
- BEGIN (ML);
-}
-<ML>^{WHITE_SPACE}+ {/* remove leading white-space */}
-<ML>{NON_WHITE_SPACE}{QUOTED_STRING}\\{EOL} {
- int len = strlen (yytext);
-
- /* remove "\\<EOL>" */
- if ('\r' == yytext[len - 2])
- len -= 3;
- else
- len -= 2;
- yytext[len] = '\0';
-
- ml_append(yytext);
-}
-<ML>{NON_WHITE_SPACE}{QUOTED_STRING}\" {
- ml_append(yytext);
- yylval.string = ml_buffer;
-
- BEGIN (INITIAL);
- return (QUOTED_STRING);
-}
-%%
-static void ml_append (char *string)
-{
- int len = strlen (string);
- int s;
-
- if (ml_free <= len) {
- ml_len += len - ml_free + 1;
- ml_buffer = (char *)realloc (ml_buffer, ml_len);
- if (NULL == ml_buffer)
- YY_FATAL_ERROR ("out of dynamic memory in ml_append");
- }
-
- s = snprintf (ml_buffer + ml_pos, ml_free, "%s", string);
- if ((0 > s) || (ml_free <= s))
- YY_FATAL_ERROR ("failed to write to multiline buffer");
-
- ml_pos += s;
- return;
-} /* ml_append */
-
diff --git a/src/Makefile.am b/src/Makefile.am
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,25 @@
+AUTOMAKE_OPTIONS = foreign no-dependencies
+
+if COMPILER_IS_GCC
+AM_CFLAGS = -Wall -Wextra
+endif
+AM_YFLAGS = -d
+
+BUILT_SOURCES = parser.h
+
+bin_PROGRAMS = collection.fcgi
+
+collection_fcgi_SOURCES = main.c \
+ oconfig.c oconfig.h aux_types.h scanner.l parser.y \
+ action_graph.c action_graph.h \
+ action_list_graphs.c action_list_graphs.h \
+ common.c common.h \
+ filesystem.c filesystem.h \
+ graph.c graph.h \
+ graph_config.c graph_config.h \
+ graph_def.c graph_def.h \
+ graph_ident.c graph_ident.h \
+ graph_instance.c graph_instance.h \
+ graph_list.c graph_list.h \
+ utils_array.c utils_array.h \
+ utils_params.c utils_params.h
diff --git a/src/action_graph.c b/src/action_graph.c
--- /dev/null
+++ b/src/action_graph.c
@@ -0,0 +1,150 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <dirent.h> /* for PATH_MAX */
+#include <assert.h>
+#include <math.h>
+
+#include <rrd.h>
+
+#include "common.h"
+#include "action_graph.h"
+#include "graph_list.h"
+#include "utils_params.h"
+#include "utils_array.h"
+
+#include <fcgiapp.h>
+#include <fcgi_stdio.h>
+
+static void emulate_graph (int argc, char **argv) /* {{{ */
+{
+ int i;
+
+ printf ("rrdtool \\\n");
+ for (i = 0; i < argc; i++)
+ {
+ if (i < (argc - 1))
+ printf (" \"%s\" \\\n", argv[i]);
+ else
+ printf (" \"%s\"\n", argv[i]);
+ }
+} /* }}} void emulate_graph */
+
+static int ag_info_print (rrd_info_t *info) /* {{{ */
+{
+ if (info->type == RD_I_VAL)
+ printf ("[info] %s = %g;\n", info->key, info->value.u_val);
+ else if (info->type == RD_I_CNT)
+ printf ("[info] %s = %lu;\n", info->key, info->value.u_cnt);
+ else if (info->type == RD_I_STR)
+ printf ("[info] %s = %s;\n", info->key, info->value.u_str);
+ else if (info->type == RD_I_INT)
+ printf ("[info] %s = %i;\n", info->key, info->value.u_int);
+ else if (info->type == RD_I_BLO)
+ printf ("[info] %s = [blob, %lu bytes];\n", info->key, info->value.u_blo.size);
+ else
+ printf ("[info] %s = [unknown type %#x];\n", info->key, info->type);
+
+ return (0);
+} /* }}} int ag_info_print */
+
+static int output_graph (rrd_info_t *info) /* {{{ */
+{
+ rrd_info_t *img;
+
+ for (img = info; img != NULL; img = img->next)
+ if ((strcmp ("image", img->key) == 0)
+ && (img->type == RD_I_BLO))
+ break;
+
+ if (img == NULL)
+ return (ENOENT);
+
+ printf ("Content-Type: image/png\n"
+ "Content-Length: %lu\n"
+ "\n",
+ img->value.u_blo.size);
+ fwrite (img->value.u_blo.ptr, img->value.u_blo.size,
+ /* nmemb = */ 1, stdout);
+
+ return (0);
+} /* }}} int output_graph */
+
+#define OUTPUT_ERROR(...) do { \
+ printf ("Content-Type: text/plain\n\n"); \
+ printf (__VA_ARGS__); \
+ return (0); \
+} while (0)
+
+int action_graph (void) /* {{{ */
+{
+ str_array_t *args;
+ graph_config_t *cfg;
+ graph_instance_t *inst;
+ rrd_info_t *info;
+ int status;
+
+ cfg = gl_graph_get_selected ();
+ if (cfg == NULL)
+ OUTPUT_ERROR ("gl_graph_get_selected () failed.\n");
+
+ inst = inst_get_selected (cfg);
+ if (inst == NULL)
+ OUTPUT_ERROR ("inst_get_selected (%p) failed.\n", (void *) cfg);
+
+ args = array_create ();
+ if (args == NULL)
+ return (ENOMEM);
+
+ array_append (args, "graph");
+ array_append (args, "-");
+ array_append (args, "--imgformat");
+ array_append (args, "PNG");
+
+ status = inst_get_rrdargs (cfg, inst, args);
+ if (status != 0)
+ {
+ array_destroy (args);
+ OUTPUT_ERROR ("inst_get_rrdargs failed with status %i.\n", status);
+ }
+
+ rrd_clear_error ();
+ info = rrd_graph_v (array_argc (args), array_argv (args));
+ if ((info == NULL) || rrd_test_error ())
+ {
+ printf ("Content-Type: text/plain\n\n");
+ printf ("rrd_graph_v failed: %s\n", rrd_get_error ());
+ emulate_graph (array_argc (args), array_argv (args));
+ }
+ else
+ {
+ int status;
+
+ status = output_graph (info);
+ if (status != 0)
+ {
+ rrd_info_t *ptr;
+
+ printf ("Content-Type: text/plain\n\n");
+ printf ("output_graph failed. Maybe the \"image\" info was not found?\n\n");
+
+ for (ptr = info; ptr != NULL; ptr = ptr->next)
+ {
+ ag_info_print (ptr);
+ }
+ }
+ }
+
+ if (info != NULL)
+ rrd_info_free (info);
+
+ array_destroy (args);
+ args = NULL;
+
+ return (0);
+} /* }}} int action_graph */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/action_graph.h b/src/action_graph.h
--- /dev/null
+++ b/src/action_graph.h
@@ -0,0 +1,7 @@
+#ifndef ACTION_GRAPH_H
+#define ACTION_GRAPH_H 1
+
+int action_graph (void);
+
+#endif /* ACTION_GRAPH_H */
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/action_list_graphs.c b/src/action_list_graphs.c
--- /dev/null
+++ b/src/action_list_graphs.c
@@ -0,0 +1,126 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "action_list_graphs.h"
+#include "graph.h"
+#include "graph_list.h"
+#include "utils_params.h"
+
+#include <fcgiapp.h>
+#include <fcgi_stdio.h>
+
+static int print_graph_inst_json (__attribute__((unused)) graph_config_t *cfg, /* {{{ */
+ graph_instance_t *inst,
+ void *user_data)
+{
+ _Bool *first;
+ graph_ident_t *ident;
+ char *json;
+
+ first = user_data;
+
+ ident = inst_get_selector (inst);
+ if (ident == NULL)
+ return (-1);
+
+ json = ident_to_json (ident);
+ if (json == NULL)
+ {
+ ident_destroy (ident);
+ return (ENOMEM);
+ }
+
+ if (*first)
+ printf ("%s", json);
+ else
+ printf (",\n%s", json);
+
+ *first = 0;
+
+ ident_destroy (ident);
+ return (0);
+} /* }}} int print_graph_inst_json */
+
+static int print_graph_json (graph_config_t *cfg, /* {{{ */
+ void *user_data)
+{
+ return (gl_graph_instance_get_all (cfg, print_graph_inst_json, user_data));
+} /* }}} int print_graph_json */
+
+static int list_graphs_json (void) /* {{{ */
+{
+ _Bool first = 1;
+
+ printf ("Content-Type: application/json\n\n");
+
+ printf ("[\n");
+ gl_graph_get_all (print_graph_json, /* user_data = */ &first);
+ printf ("\n]");
+
+ return (0);
+} /* }}} int list_graphs_json */
+
+static int print_graph_inst_html (graph_config_t *cfg, /* {{{ */
+ graph_instance_t *inst,
+ __attribute__((unused)) void *user_data)
+{
+ char params[1024];
+ char desc[1024];
+
+ memset (params, 0, sizeof (params));
+ inst_get_params (cfg, inst, params, sizeof (params));
+
+ memset (desc, 0, sizeof (desc));
+ inst_describe (cfg, inst, desc, sizeof (desc));
+
+ printf (" <li><a href=\"test.fcgi?action=graph;%s\">%s</a></li>\n",
+ params, desc);
+
+ return (0);
+} /* }}} int print_graph_inst_html */
+
+static int print_graph_html (graph_config_t *cfg, /* {{{ */
+ __attribute__((unused)) void *user_data)
+{
+ char buffer[1024];
+
+ memset (buffer, 0, sizeof (buffer));
+ graph_get_title (cfg, buffer, sizeof (buffer));
+
+ printf (" <li>%s\n <ul>\n", buffer);
+ gl_graph_instance_get_all (cfg, print_graph_inst_html, /* user_data = */ NULL);
+ printf (" </ul></li>\n");
+
+ return (0);
+} /* }}} int print_graph_html */
+
+static int list_graphs_html (void) /* {{{ */
+{
+ printf ("Content-Type: text/html\n\n");
+
+ printf ("<ul>\n");
+ gl_graph_get_all (print_graph_html, /* user_data = */ NULL);
+ printf ("</ul>\n");
+
+ return (0);
+} /* }}} int list_graphs_html */
+
+int action_list_graphs (void) /* {{{ */
+{
+ const char *format;
+
+ gl_update ();
+
+ format = param ("format");
+ if (format == NULL)
+ format = "html";
+
+ if (strcmp ("json", format) == 0)
+ return (list_graphs_json ());
+ else
+ return (list_graphs_html ());
+} /* }}} int action_list_graphs */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/action_list_graphs.h b/src/action_list_graphs.h
--- /dev/null
+++ b/src/action_list_graphs.h
@@ -0,0 +1,7 @@
+#ifndef ACTION_LIST_GRAPHS_H
+#define ACTION_LIST_GRAPHS_H 1
+
+int action_list_graphs (void);
+
+#endif /* ACTION_LIST_GRAPHS_H */
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/aux_types.h b/src/aux_types.h
--- /dev/null
+++ b/src/aux_types.h
@@ -0,0 +1,18 @@
+#ifndef AUX_TYPES_H
+#define AUX_TYPES_H 1
+
+struct statement_list_s
+{
+ oconfig_item_t *statement;
+ int statement_num;
+};
+typedef struct statement_list_s statement_list_t;
+
+struct argument_list_s
+{
+ oconfig_value_t *argument;
+ int argument_num;
+};
+typedef struct argument_list_s argument_list_t;
+
+#endif /* AUX_TYPES_H */
diff --git a/src/common.c b/src/common.c
--- /dev/null
+++ b/src/common.c
@@ -0,0 +1,193 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <assert.h>
+#include <math.h>
+
+#include <rrd.h>
+
+#include "common.h"
+#include "graph_list.h"
+
+#include <fcgiapp.h>
+#include <fcgi_stdio.h>
+
+size_t c_strlcat (char *dst, const char *src, size_t size) /* {{{ */
+{
+ size_t retval;
+ size_t dst_len;
+ size_t src_len;
+
+ dst_len = strlen (dst);
+ src_len = strlen (src);
+ retval = dst_len + src_len;
+
+ if ((dst_len + 1) >= size)
+ return (retval);
+
+ dst += dst_len;
+ size -= dst_len;
+ assert (size >= 2);
+
+ /* Result will be truncated. */
+ if (src_len >= size)
+ src_len = size - 1;
+
+ memcpy (dst, src, src_len);
+ dst[src_len] = 0;
+
+ return (retval);
+} /* }}} size_t c_strlcat */
+
+int ds_list_from_rrd_file (char *file, /* {{{ */
+ size_t *ret_dses_num, char ***ret_dses)
+{
+ char *rrd_argv[] = { "info", file, NULL };
+ int rrd_argc = (sizeof (rrd_argv) / sizeof (rrd_argv[0])) - 1;
+
+ rrd_info_t *info;
+ rrd_info_t *ptr;
+
+ char **dses = NULL;
+ size_t dses_num = 0;
+
+ info = rrd_info (rrd_argc, rrd_argv);
+ if (info == NULL)
+ {
+ printf ("%s: rrd_info (%s) failed.\n", __func__, file);
+ return (-1);
+ }
+
+ for (ptr = info; ptr != NULL; ptr = ptr->next)
+ {
+ size_t keylen;
+ size_t dslen;
+ char *ds;
+ char **tmp;
+
+ if (strncmp ("ds[", ptr->key, strlen ("ds[")) != 0)
+ continue;
+
+ keylen = strlen (ptr->key);
+ if (keylen < strlen ("ds[?].index"))
+ continue;
+
+ dslen = keylen - strlen ("ds[].index");
+ assert (dslen >= 1);
+
+ if (strcmp ("].index", ptr->key + (strlen ("ds[") + dslen)) != 0)
+ continue;
+
+ ds = malloc (dslen + 1);
+ if (ds == NULL)
+ continue;
+
+ memcpy (ds, ptr->key + strlen ("ds["), dslen);
+ ds[dslen] = 0;
+
+ tmp = realloc (dses, sizeof (*dses) * (dses_num + 1));
+ if (tmp == NULL)
+ {
+ free (ds);
+ continue;
+ }
+ dses = tmp;
+
+ dses[dses_num] = ds;
+ dses_num++;
+ }
+
+ rrd_info_free (info);
+
+ if (dses_num < 1)
+ {
+ assert (dses == NULL);
+ return (ENOENT);
+ }
+
+ *ret_dses_num = dses_num;
+ *ret_dses = dses;
+
+ return (0);
+} /* }}} int ds_list_from_rrd_file */
+
+static int hsv_to_rgb (double *hsv, double *rgb) /* {{{ */
+{
+ double c = hsv[2] * hsv[1];
+ double h = hsv[0] / 60.0;
+ double x = c * (1.0 - fabs (fmod (h, 2.0) - 1));
+ double m = hsv[2] - c;
+
+ rgb[0] = 0.0;
+ rgb[1] = 0.0;
+ rgb[2] = 0.0;
+
+ if ((0.0 <= h) && (h < 1.0)) { rgb[0] = 1.0; rgb[1] = x; rgb[2] = 0.0; }
+ else if ((1.0 <= h) && (h < 2.0)) { rgb[0] = x; rgb[1] = 1.0; rgb[2] = 0.0; }
+ else if ((2.0 <= h) && (h < 3.0)) { rgb[0] = 0.0; rgb[1] = 1.0; rgb[2] = x; }
+ else if ((3.0 <= h) && (h < 4.0)) { rgb[0] = 0.0; rgb[1] = x; rgb[2] = 1.0; }
+ else if ((4.0 <= h) && (h < 5.0)) { rgb[0] = x; rgb[1] = 0.0; rgb[2] = 1.0; }
+ else if ((5.0 <= h) && (h < 6.0)) { rgb[0] = 1.0; rgb[1] = 0.0; rgb[2] = x; }
+
+ rgb[0] += m;
+ rgb[1] += m;
+ rgb[2] += m;
+
+ return (0);
+} /* }}} int hsv_to_rgb */
+
+static uint32_t rgb_to_uint32 (double *rgb) /* {{{ */
+{
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+
+ r = (uint8_t) (255.0 * rgb[0]);
+ g = (uint8_t) (255.0 * rgb[1]);
+ b = (uint8_t) (255.0 * rgb[2]);
+
+ return ((((uint32_t) r) << 16)
+ | (((uint32_t) g) << 8)
+ | ((uint32_t) b));
+} /* }}} uint32_t rgb_to_uint32 */
+
+uint32_t get_random_color (void) /* {{{ */
+{
+ double hsv[3] = { 0.0, 1.0, 1.0 };
+ double rgb[3] = { 0.0, 0.0, 0.0 };
+
+ hsv[0] = 360.0 * ((double) rand ()) / (((double) RAND_MAX) + 1.0);
+
+ hsv_to_rgb (hsv, rgb);
+
+ return (rgb_to_uint32 (rgb));
+} /* }}} uint32_t get_random_color */
+
+int print_debug (const char *format, ...) /* {{{ */
+{
+ static _Bool have_header = 0;
+
+ va_list ap;
+ int status;
+
+ if (!have_header)
+ {
+ printf ("Content-Type: text/plain\n\n");
+ have_header = 1;
+ }
+
+ va_start (ap, format);
+ status = vprintf (format, ap);
+ va_end (ap);
+
+ return (status);
+} /* }}} int print_debug */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/common.h b/src/common.h
--- /dev/null
+++ b/src/common.h
@@ -0,0 +1,24 @@
+#ifndef COMMON_H
+#define COMMON_H 1
+
+#include <stdint.h>
+#include <inttypes.h>
+
+int print_debug (const char *format, ...)
+ __attribute__((format(printf,1,2)));
+#if 0
+# define DEBUG(...) print_debug (__VA_ARGS__)
+#else
+# define DEBUG(...) /**/
+#endif
+
+size_t c_strlcat (char *dst, const char *src, size_t size);
+#define strlcat c_strlcat
+
+int ds_list_from_rrd_file (char *file,
+ size_t *ret_dses_num, char ***ret_dses);
+
+uint32_t get_random_color (void);
+
+#endif /* COMMON_H */
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/filesystem.c b/src/filesystem.c
--- /dev/null
+++ b/src/filesystem.c
@@ -0,0 +1,297 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#include "filesystem.h"
+
+struct fs_scan_dir_data_s /* {{{ */
+{
+ fs_ident_cb_t callback;
+ void *user_data;
+
+ char *host;
+ char *plugin;
+ char *plugin_instance;
+ char *type;
+ char *type_instance;
+}; /* }}} */
+typedef struct fs_scan_dir_data_s fs_scan_dir_data_t;
+
+typedef int (*callback_type_t) (const char *type, void *user_data);
+typedef int (*callback_plugin_t) (const char *plugin, void *user_data);
+typedef int (*callback_host_t) (const char *host, void *user_data);
+
+/*
+ * Directory and file walking functions
+ */
+static int foreach_rrd_file (const char *dir, /* {{{ */
+ int (*callback) (const char *, void *),
+ void *user_data)
+{
+ DIR *dh;
+ struct dirent *entry;
+ int status;
+
+ if (callback == NULL)
+ return (EINVAL);
+
+ dh = opendir (dir);
+ if (dh == NULL)
+ return (errno);
+
+ while ((entry = readdir (dh)) != NULL)
+ {
+ struct stat statbuf;
+ char abspath[PATH_MAX + 1];
+ size_t d_name_len;
+
+ if (entry->d_name[0] == '.')
+ continue;
+
+ d_name_len = strlen (entry->d_name);
+ if (d_name_len <= 4)
+ continue;
+
+ if (strcasecmp (".rrd", entry->d_name + (d_name_len - 4)) != 0)
+ continue;
+
+ snprintf (abspath, sizeof (abspath), "%s/%s", dir, entry->d_name);
+ abspath[sizeof (abspath) - 1] = 0;
+
+ memset (&statbuf, 0, sizeof (statbuf));
+
+ status = stat (abspath, &statbuf);
+ if (status != 0)
+ continue;
+
+ if (!S_ISREG (statbuf.st_mode))
+ continue;
+
+ entry->d_name[d_name_len - 4] = 0;
+
+ status = (*callback) (entry->d_name, user_data);
+ if (status != 0)
+ break;
+ } /* while (readdir) */
+
+ closedir (dh);
+ return (status);
+} /* }}} int foreach_rrd_file */
+
+static int foreach_dir (const char *dir, /* {{{ */
+ int (*callback) (const char *, void *),
+ void *user_data)
+{
+ DIR *dh;
+ struct dirent *entry;
+ int status = 0;
+
+ if (callback == NULL)
+ return (EINVAL);
+
+ dh = opendir (dir);
+ if (dh == NULL)
+ return (errno);
+
+ while ((entry = readdir (dh)) != NULL)
+ {
+ struct stat statbuf;
+ char abspath[PATH_MAX + 1];
+
+ if (entry->d_name[0] == '.')
+ continue;
+
+ snprintf (abspath, sizeof (abspath), "%s/%s", dir, entry->d_name);
+ abspath[sizeof (abspath) - 1] = 0;
+
+ memset (&statbuf, 0, sizeof (statbuf));
+
+ status = stat (abspath, &statbuf);
+ if (status != 0)
+ continue;
+
+ if (!S_ISDIR (statbuf.st_mode))
+ continue;
+
+ status = (*callback) (entry->d_name, user_data);
+ if (status != 0)
+ break;
+ } /* while (readdir) */
+
+ closedir (dh);
+ return (status);
+} /* }}} int foreach_dir */
+
+static int foreach_type (const char *host, const char *plugin, /* {{{ */
+ callback_type_t callback, void *user_data)
+{
+ char abspath[PATH_MAX + 1];
+
+ if ((host == NULL) || (plugin == NULL))
+ return (EINVAL);
+
+ snprintf (abspath, sizeof (abspath), "%s/%s/%s", DATA_DIR, host, plugin);
+ abspath[sizeof (abspath) - 1] = 0;
+
+ return (foreach_rrd_file (abspath, callback, user_data));
+} /* }}} int foreach_type */
+
+static int foreach_plugin (const char *host, /* {{{ */
+ callback_plugin_t callback,
+ void *user_data)
+{
+ char abspath[PATH_MAX + 1];
+
+ if (host == NULL)
+ return (EINVAL);
+
+ snprintf (abspath, sizeof (abspath), "%s/%s", DATA_DIR, host);
+ abspath[sizeof (abspath) - 1] = 0;
+
+ return (foreach_dir (abspath, callback, user_data));
+} /* }}} int foreach_plugin */
+
+static int foreach_host (callback_host_t callback, /* {{{ */
+ void *user_data)
+{
+ return (foreach_dir (DATA_DIR, callback, user_data));
+} /* }}} int foreach_host */
+
+/*
+ * Functions building "fs_scan_dir_data_t" and calling the user-supplied
+ * callback eventually.
+ */
+static int scan_type (const char *type, void *user_data) /* {{{ */
+{
+ fs_scan_dir_data_t *data = user_data;
+ graph_ident_t *ident;
+ int status;
+
+ if ((type == NULL) || (data == NULL))
+ return (EINVAL);
+
+ if ((data->type != NULL) || (data->type_instance != NULL))
+ return (EINVAL);
+
+ data->type = strdup (type);
+ if (data->type == NULL)
+ return (ENOMEM);
+
+ data->type_instance = strchr (data->type, '-');
+ if (data->type_instance != NULL)
+ {
+ *data->type_instance = 0;
+ data->type_instance++;
+ }
+ else
+ {
+ data->type_instance = data->type + strlen (data->type);
+ }
+
+ ident = ident_create (data->host,
+ data->plugin, data->plugin_instance,
+ data->type, data->type_instance);
+ if (ident == NULL)
+ {
+ status = -1;
+ }
+ else
+ {
+ status = (*data->callback) (ident, data->user_data);
+ ident_destroy (ident);
+ }
+
+ free (data->type);
+ data->type = NULL;
+ data->type_instance = NULL;
+
+ return (status);
+} /* }}} int scan_type */
+
+static int scan_plugin (const char *plugin, void *user_data) /* {{{ */
+{
+ fs_scan_dir_data_t *data = user_data;
+ int status;
+
+ if ((plugin == NULL) || (data == NULL))
+ return (EINVAL);
+
+ if ((data->plugin != NULL) || (data->plugin_instance != NULL))
+ return (EINVAL);
+
+ data->plugin = strdup (plugin);
+ if (data->plugin == NULL)
+ return (ENOMEM);
+
+ data->plugin_instance = strchr (data->plugin, '-');
+ if (data->plugin_instance != NULL)
+ {
+ *data->plugin_instance = 0;
+ data->plugin_instance++;
+ }
+ else
+ {
+ data->plugin_instance = data->plugin + strlen (data->plugin);
+ }
+
+ status = foreach_type (data->host, plugin, scan_type, data);
+
+ free (data->plugin);
+ data->plugin = NULL;
+ data->plugin_instance = NULL;
+
+ return (status);
+} /* }}} int scan_plugin */
+
+static int scan_host (const char *host, void *user_data) /* {{{ */
+{
+ fs_scan_dir_data_t *data = user_data;
+ int status;
+
+ if ((host == NULL) || (data == NULL))
+ return (EINVAL);
+
+ if (data->host != NULL)
+ return (EINVAL);
+
+ data->host = strdup (host);
+ if (data->host == NULL)
+ return (ENOMEM);
+
+ status = foreach_plugin (host, scan_plugin, data);
+
+ free (data->host);
+ data->host = NULL;
+
+ return (status);
+} /* }}} int scan_host */
+
+/*
+ * Public function
+ */
+int fs_scan (fs_ident_cb_t callback, void *user_data) /* {{{ */
+{
+ fs_scan_dir_data_t data;
+
+ memset (&data, 0, sizeof (data));
+ data.callback = callback;
+ data.user_data = user_data;
+
+ data.host = NULL;
+ data.plugin = NULL;
+ data.plugin_instance = NULL;
+ data.type = NULL;
+ data.type_instance = NULL;
+
+ foreach_host (scan_host, &data);
+
+ return (0);
+} /* }}} int fs_scan */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/filesystem.h b/src/filesystem.h
--- /dev/null
+++ b/src/filesystem.h
@@ -0,0 +1,13 @@
+#ifndef FILESYSTEM_G
+#define FILESYSTEM_G 1
+
+#include "graph_ident.h"
+
+#define DATA_DIR "/var/lib/collectd/rrd"
+
+typedef int (*fs_ident_cb_t) (const graph_ident_t *ident, void *user_data);
+
+int fs_scan (fs_ident_cb_t callback, void *user_data);
+
+#endif /* FILESYSTEM_G */
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/graph.c b/src/graph.c
--- /dev/null
+++ b/src/graph.c
@@ -0,0 +1,290 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "graph.h"
+#include "graph_list.h"
+#include "graph_ident.h"
+#include "graph_def.h"
+#include "graph_config.h"
+#include "common.h"
+#include "filesystem.h"
+#include "utils_params.h"
+
+#include <fcgiapp.h>
+#include <fcgi_stdio.h>
+
+/*
+ * Data types
+ */
+struct graph_config_s /* {{{ */
+{
+ graph_ident_t *select;
+
+ char *title;
+ char *vertical_label;
+
+ graph_def_t *defs;
+
+ graph_instance_t *instances;
+}; /* }}} struct graph_config_s */
+
+/*
+ * Private functions
+ */
+static graph_instance_t *graph_find_instance (graph_config_t *cfg, /* {{{ */
+ const graph_ident_t *ident)
+{
+ if ((cfg == NULL) || (ident == NULL))
+ return (NULL);
+
+ return (inst_find_matching (cfg->instances, ident));
+} /* }}} graph_instance_t *graph_find_instance */
+
+/*
+ * Config functions
+ */
+static graph_ident_t *graph_config_get_selector (const oconfig_item_t *ci) /* {{{ */
+{
+ char *host = NULL;
+ char *plugin = NULL;
+ char *plugin_instance = NULL;
+ char *type = NULL;
+ char *type_instance = NULL;
+ graph_ident_t *ret;
+ int i;
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child;
+
+ child = ci->children + i;
+
+ if (strcasecmp ("Host", child->key) == 0)
+ graph_config_get_string (child, &host);
+ else if (strcasecmp ("Plugin", child->key) == 0)
+ graph_config_get_string (child, &plugin);
+ else if (strcasecmp ("PluginInstance", child->key) == 0)
+ graph_config_get_string (child, &plugin_instance);
+ else if (strcasecmp ("Type", child->key) == 0)
+ graph_config_get_string (child, &type);
+ else if (strcasecmp ("TypeInstance", child->key) == 0)
+ graph_config_get_string (child, &type_instance);
+ /* else: ignore all other directives here. */
+ } /* for */
+
+ ret = ident_create (host, plugin, plugin_instance, type, type_instance);
+
+ free (host);
+ free (plugin);
+ free (plugin_instance);
+ free (type);
+ free (type_instance);
+
+ return (ret);
+} /* }}} int graph_config_get_selector */
+
+/*
+ * Global functions
+ */
+graph_config_t *graph_create (const graph_ident_t *selector) /* {{{ */
+{
+ graph_config_t *cfg;
+
+ cfg = malloc (sizeof (*cfg));
+ if (cfg == NULL)
+ return (NULL);
+ memset (cfg, 0, sizeof (*cfg));
+
+ if (selector != NULL)
+ cfg->select = ident_clone (selector);
+ else
+ cfg->select = NULL;
+
+ cfg->title = NULL;
+ cfg->vertical_label = NULL;
+ cfg->defs = NULL;
+ cfg->instances = NULL;
+
+ return (cfg);
+} /* }}} int graph_create */
+
+void graph_destroy (graph_config_t *cfg) /* {{{ */
+{
+ if (cfg == NULL)
+ return;
+
+ ident_destroy (cfg->select);
+
+ free (cfg->title);
+ free (cfg->vertical_label);
+
+ def_destroy (cfg->defs);
+ inst_destroy (cfg->instances);
+} /* }}} void graph_destroy */
+
+int graph_config_add (const oconfig_item_t *ci) /* {{{ */
+{
+ graph_ident_t *select;
+ graph_config_t *cfg = NULL;
+ int i;
+
+ select = graph_config_get_selector (ci);
+ if (select == NULL)
+ return (EINVAL);
+
+ cfg = graph_create (/* selector = */ NULL);
+ if (cfg == NULL)
+ return (ENOMEM);
+
+ cfg->select = select;
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child;
+
+ child = ci->children + i;
+
+ if (strcasecmp ("Title", child->key) == 0)
+ graph_config_get_string (child, &cfg->title);
+ else if (strcasecmp ("VerticalLabel", child->key) == 0)
+ graph_config_get_string (child, &cfg->vertical_label);
+ else if (strcasecmp ("DEF", child->key) == 0)
+ def_config (cfg, child);
+ } /* for */
+
+ gl_add_graph (cfg);
+
+ return (0);
+} /* }}} graph_config_add */
+
+int graph_add_file (graph_config_t *cfg, const graph_ident_t *file) /* {{{ */
+{
+ graph_instance_t *inst;
+
+ inst = graph_find_instance (cfg, file);
+ if (inst == NULL)
+ {
+ inst = inst_create (cfg, file);
+ if (inst == NULL)
+ return (ENOMEM);
+
+ if (cfg->instances == NULL)
+ cfg->instances = inst;
+ else
+ inst_append (cfg->instances, inst);
+ }
+
+ return (inst_add_file (inst, file));
+} /* }}} int graph_add_file */
+
+int graph_get_title (graph_config_t *cfg, /* {{{ */
+ char *buffer, size_t buffer_size)
+{
+ if ((cfg == NULL) || (buffer == NULL) || (buffer_size < 1))
+ return (EINVAL);
+
+ if (cfg->title == NULL)
+ cfg->title = ident_to_string (cfg->select);
+
+ if (cfg->title == NULL)
+ return (ENOMEM);
+
+ strncpy (buffer, cfg->title, buffer_size);
+ buffer[buffer_size - 1] = 0;
+
+ return (0);
+} /* }}} int graph_get_title */
+
+graph_ident_t *graph_get_selector (graph_config_t *cfg) /* {{{ */
+{
+ if (cfg == NULL)
+ return (NULL);
+
+ return (ident_clone (cfg->select));
+} /* }}} graph_ident_t *graph_get_selector */
+
+graph_instance_t *graph_get_instances (graph_config_t *cfg) /* {{{ */
+{
+ if (cfg == NULL)
+ return (NULL);
+
+ return (cfg->instances);
+} /* }}} graph_instance_t *graph_get_instances */
+
+graph_def_t *graph_get_defs (graph_config_t *cfg) /* {{{ */
+{
+ if (cfg == NULL)
+ return (NULL);
+
+ return (cfg->defs);
+} /* }}} graph_def_t *graph_get_defs */
+
+int graph_add_def (graph_config_t *cfg, graph_def_t *def) /* {{{ */
+{
+ if ((cfg == NULL) || (def == NULL))
+ return (EINVAL);
+
+ if (cfg->defs == NULL)
+ {
+ cfg->defs = def;
+ return (0);
+ }
+
+ return (def_append (cfg->defs, def));
+} /* }}} int graph_add_def */
+
+_Bool graph_matches (graph_config_t *cfg, const graph_ident_t *ident) /* {{{ */
+{
+ if ((cfg == NULL) || (ident == NULL))
+ return (0);
+
+ return (ident_matches (cfg->select, ident));
+} /* }}} _Bool graph_matches */
+
+int graph_compare (graph_config_t *cfg, const graph_ident_t *ident) /* {{{ */
+{
+ if ((cfg == NULL) || (ident == NULL))
+ return (0);
+
+ return (ident_compare (cfg->select, ident));
+} /* }}} int graph_compare */
+
+int graph_clear_instances (graph_config_t *cfg) /* {{{ */
+{
+ if (cfg == NULL)
+ return (EINVAL);
+
+ inst_destroy (cfg->instances);
+ cfg->instances = NULL;
+
+ return (0);
+} /* }}} int graph_clear_instances */
+
+int graph_get_rrdargs (graph_config_t *cfg, graph_instance_t *inst, /* {{{ */
+ str_array_t *args)
+{
+ if ((cfg == NULL) || (inst == NULL) || (args == NULL))
+ return (EINVAL);
+
+ if (cfg->title != NULL)
+ {
+ array_append (args, "-t");
+ array_append (args, cfg->title);
+ }
+
+ if (cfg->vertical_label != NULL)
+ {
+ array_append (args, "-v");
+ array_append (args, cfg->vertical_label);
+ }
+
+ return (0);
+} /* }}} int graph_get_rrdargs */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/graph.h b/src/graph.h
--- /dev/null
+++ b/src/graph.h
@@ -0,0 +1,48 @@
+#ifndef GRAPH_H
+#define GRAPH_H 1
+
+/*
+ * Data types
+ */
+struct graph_config_s;
+typedef struct graph_config_s graph_config_t;
+
+#include "graph_def.h"
+#include "graph_ident.h"
+#include "graph_instance.h"
+#include "oconfig.h"
+#include "utils_array.h"
+
+/*
+ * Functions
+ */
+graph_config_t *graph_create (const graph_ident_t *selector);
+
+void graph_destroy (graph_config_t *graph);
+
+int graph_config_add (const oconfig_item_t *ci);
+
+int graph_add_file (graph_config_t *cfg, const graph_ident_t *file);
+
+int graph_get_title (graph_config_t *cfg,
+ char *buffer, size_t buffer_size);
+
+graph_ident_t *graph_get_selector (graph_config_t *cfg);
+
+graph_instance_t *graph_get_instances (graph_config_t *cfg);
+
+graph_def_t *graph_get_defs (graph_config_t *cfg);
+
+int graph_add_def (graph_config_t *cfg, graph_def_t *def);
+
+_Bool graph_matches (graph_config_t *cfg, const graph_ident_t *ident);
+
+int graph_compare (graph_config_t *cfg, const graph_ident_t *ident);
+
+int graph_clear_instances (graph_config_t *cfg);
+
+int graph_get_rrdargs (graph_config_t *cfg, graph_instance_t *inst,
+ str_array_t *args);
+
+#endif /* GRAPH_H */
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/graph_config.c b/src/graph_config.c
--- /dev/null
+++ b/src/graph_config.c
@@ -0,0 +1,116 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include "graph_config.h"
+#include "graph_list.h"
+#include "oconfig.h"
+#include "common.h"
+
+#define CONFIG_FILE "/usr/lib/cgi-bin/octo/collection.conf"
+
+time_t last_read_mtime = 0;
+
+static int dispatch_config (const oconfig_item_t *ci) /* {{{ */
+{
+ int i;
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child;
+
+ child = ci->children + i;
+ if (strcasecmp ("Graph", child->key) == 0)
+ graph_config_add (child);
+ else
+ {
+ DEBUG ("Unknown config option: %s", child->key);
+ }
+ }
+
+ return (0);
+} /* }}} int dispatch_config */
+
+static int internal_read_config (void) /* {{{ */
+{
+ oconfig_item_t *ci;
+
+ ci = oconfig_parse_file (CONFIG_FILE);
+ if (ci == NULL)
+ return (-1);
+
+ dispatch_config (ci);
+
+ oconfig_free (ci);
+
+ gl_config_submit ();
+
+ return (0);
+} /* }}} int internal_read_config */
+
+static time_t get_config_mtime (void) /* {{{ */
+{
+ struct stat statbuf;
+ int status;
+
+ memset (&statbuf, 0, sizeof (statbuf));
+ status = stat (CONFIG_FILE, &statbuf);
+ if (status != 0)
+ return (0);
+
+ return (statbuf.st_mtime);
+} /* }}} time_t get_config_mtime */
+
+int graph_read_config (void) /* {{{ */
+{
+ time_t mtime;
+
+ mtime = get_config_mtime ();
+
+ if (mtime <= last_read_mtime)
+ return (0);
+
+ internal_read_config ();
+
+ last_read_mtime = mtime;
+
+ return (0);
+} /* }}} int graph_read_config */
+
+int graph_config_get_string (const oconfig_item_t *ci, /* {{{ */
+ char **ret_str)
+{
+ char *tmp;
+
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ return (EINVAL);
+
+ tmp = strdup (ci->values[0].value.string);
+ if (tmp == NULL)
+ return (ENOMEM);
+
+ free (*ret_str);
+ *ret_str = tmp;
+
+ return (0);
+} /* }}} int graph_config_get_string */
+
+int graph_config_get_bool (const oconfig_item_t *ci, /* {{{ */
+ _Bool *ret_bool)
+{
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
+ return (EINVAL);
+
+ if (ci->values[0].value.boolean)
+ *ret_bool = 1;
+ else
+ *ret_bool = 0;
+
+ return (0);
+} /* }}} int graph_config_get_bool */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/graph_config.h b/src/graph_config.h
--- /dev/null
+++ b/src/graph_config.h
@@ -0,0 +1,12 @@
+#ifndef GRAPH_CONFIG_H
+#define GRAPH_CONFIG_H 1
+
+#include "oconfig.h"
+
+int graph_read_config (void);
+
+int graph_config_get_string (const oconfig_item_t *ci, char **ret_str);
+int graph_config_get_bool (const oconfig_item_t *ci, _Bool *ret_bool);
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
+#endif /* GRAPH_CONFIG_H */
diff --git a/src/graph_def.c b/src/graph_def.c
--- /dev/null
+++ b/src/graph_def.c
@@ -0,0 +1,348 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "graph_def.h"
+#include "graph.h"
+#include "graph_config.h"
+#include "common.h"
+#include "oconfig.h"
+
+#include <fcgiapp.h>
+#include <fcgi_stdio.h>
+
+/*
+ * Data structures
+ */
+struct graph_def_s
+{
+ graph_ident_t *select;
+
+ char *ds_name;
+ char *legend;
+ uint32_t color;
+ _Bool stack;
+ _Bool area;
+ char *format;
+
+ graph_def_t *next;
+};
+
+/*
+ * Private functions
+ */
+#define DEF_CONFIG_FIELD(field) \
+static int def_config_##field (const oconfig_item_t *ci, graph_ident_t *ident) \
+{ \
+ char *tmp = NULL; \
+ int status = graph_config_get_string (ci, &tmp); \
+ if (status != 0) \
+ return (status); \
+ ident_set_##field (ident, tmp); \
+ free (tmp); \
+ return (0); \
+} /* }}} int def_config_field */
+
+DEF_CONFIG_FIELD (host);
+DEF_CONFIG_FIELD (plugin);
+DEF_CONFIG_FIELD (plugin_instance);
+DEF_CONFIG_FIELD (type);
+DEF_CONFIG_FIELD (type_instance);
+
+#undef DEF_CONFIG_FIELD
+
+static int def_config_color (const oconfig_item_t *ci, uint32_t *ret_color) /* {{{ */
+{
+ char *tmp;
+ char *endptr;
+ uint32_t color;
+
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ return (EINVAL);
+
+ tmp = ci->values[0].value.string;
+
+ endptr = NULL;
+ errno = 0;
+ color = (uint32_t) strtoul (tmp, &endptr, /* base = */ 16);
+ if ((errno != 0) || (endptr == tmp) || (color > 0x00ffffff))
+ return (EINVAL);
+
+ *ret_color = color;
+
+ return (0);
+} /* }}} int def_config_color */
+
+static graph_def_t *def_config_get_obj (graph_config_t *cfg, /* {{{ */
+ const oconfig_item_t *ci)
+{
+ graph_ident_t *ident;
+ char *ds_name = NULL;
+ graph_def_t *def;
+ int i;
+
+ ident = graph_get_selector (cfg);
+ if (ident == NULL)
+ {
+ fprintf (stderr, "def_config_get_obj: graph_get_selector failed");
+ return (NULL);
+ }
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child;
+
+#define HANDLE_FIELD(name,field) \
+ else if (strcasecmp (name, child->key) == 0) \
+ def_config_##field (child, ident)
+
+ child = ci->children + i;
+ if (strcasecmp ("DSName", child->key) == 0)
+ graph_config_get_string (child, &ds_name);
+
+ HANDLE_FIELD ("Host", host);
+ HANDLE_FIELD ("Plugin", plugin);
+ HANDLE_FIELD ("PluginInstance", plugin_instance);
+ HANDLE_FIELD ("Type", type);
+ HANDLE_FIELD ("TypeInstance", type_instance);
+
+#undef HANDLE_FIELD
+ }
+
+ def = def_create (cfg, ident, ds_name);
+ if (def == NULL)
+ {
+ fprintf (stderr, "def_config_get_obj: def_create failed\n");
+ ident_destroy (ident);
+ free (ds_name);
+ return (NULL);
+ }
+
+ ident_destroy (ident);
+ free (ds_name);
+
+ return (def);
+} /* }}} graph_def_t *def_config_get_obj */
+
+/*
+ * Public functions
+ */
+graph_def_t *def_create (graph_config_t *cfg, graph_ident_t *ident, /* {{{ */
+ const char *ds_name)
+{
+ graph_ident_t *selector;
+ graph_def_t *ret;
+
+ if ((cfg == NULL) || (ident == NULL) || (ds_name == NULL))
+ return (NULL);
+
+ selector = graph_get_selector (cfg);
+ if (selector == NULL)
+ return (NULL);
+
+ ret = malloc (sizeof (*ret));
+ if (ret == NULL)
+ {
+ ident_destroy (selector);
+ return (NULL);
+ }
+ memset (ret, 0, sizeof (*ret));
+ ret->legend = NULL;
+ ret->format = NULL;
+
+ ret->ds_name = strdup (ds_name);
+ if (ret->ds_name == NULL)
+ {
+ ident_destroy (selector);
+ free (ret);
+ return (NULL);
+ }
+
+ ret->color = get_random_color ();
+ ret->next = NULL;
+
+ ret->select = ident_copy_with_selector (selector, ident,
+ IDENT_FLAG_REPLACE_ALL);
+ if (ret->select == NULL)
+ {
+ ident_destroy (selector);
+ free (ret->ds_name);
+ free (ret);
+ return (NULL);
+ }
+
+ ident_destroy (selector);
+ return (ret);
+} /* }}} graph_def_t *def_create */
+
+void def_destroy (graph_def_t *def) /* {{{ */
+{
+ graph_def_t *next;
+
+ if (def == NULL)
+ return;
+
+ next = def->next;
+
+ ident_destroy (def->select);
+
+ free (def->ds_name);
+ free (def->legend);
+ free (def->format);
+
+ free (def);
+
+ def_destroy (next);
+} /* }}} void def_destroy */
+
+int def_config (graph_config_t *cfg, const oconfig_item_t *ci) /* {{{ */
+{
+ graph_def_t *def;
+ int i;
+
+ def = def_config_get_obj (cfg, ci);
+ if (def == NULL)
+ return (EINVAL);
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child;
+
+ child = ci->children + i;
+ if (strcasecmp ("Legend", child->key) == 0)
+ graph_config_get_string (child, &def->legend);
+ else if (strcasecmp ("Color", child->key) == 0)
+ def_config_color (child, &def->color);
+ else if (strcasecmp ("Stack", child->key) == 0)
+ graph_config_get_bool (child, &def->stack);
+ else if (strcasecmp ("Area", child->key) == 0)
+ graph_config_get_bool (child, &def->area);
+ else if (strcasecmp ("Format", child->key) == 0)
+ graph_config_get_string (child, &def->format);
+ else
+ fprintf (stderr, "def_config: Ignoring unknown config option \"%s\"",
+ child->key);
+ }
+
+ return (graph_add_def (cfg, def));
+} /* }}} int def_config */
+
+int def_append (graph_def_t *head, graph_def_t *def) /* {{{ */
+{
+ graph_def_t *ptr;
+
+ if ((head == NULL) || (def == NULL))
+ return (EINVAL);
+
+ ptr = head;
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = def;
+
+ return (0);
+} /* }}} int def_append */
+
+graph_def_t *def_search (graph_def_t *head, graph_ident_t *ident, /* {{{ */
+ const char *ds_name)
+{
+ graph_def_t *ptr;
+
+ if ((head == NULL) || (ident == NULL) || (ds_name == NULL))
+ return (NULL);
+
+ for (ptr = head; ptr != NULL; ptr = ptr->next)
+ {
+ if (!ident_matches (ptr->select, ident))
+ continue;
+
+ if (strcmp (ptr->ds_name, ds_name) == 0)
+ return (ptr);
+ }
+
+ return (NULL);
+} /* }}} graph_def_t *def_search */
+
+_Bool def_matches (graph_def_t *def, graph_ident_t *ident) /* {{{ */
+{
+ return (ident_matches (def->select, ident));
+} /* }}} _Bool def_matches */
+
+int def_foreach (graph_def_t *def, def_callback_t callback, /* {{{ */
+ void *user_data)
+{
+ graph_def_t *ptr;
+
+ if ((def == NULL) || (callback == NULL))
+ return (EINVAL);
+
+ for (ptr = def; ptr != NULL; ptr = ptr->next)
+ {
+ int status;
+
+ status = (*callback) (ptr, user_data);
+ if (status != 0)
+ return (status);
+ }
+
+ return (0);
+} /* }}} int def_foreach */
+
+int def_get_rrdargs (graph_def_t *def, graph_ident_t *ident, /* {{{ */
+ str_array_t *args)
+{
+ char *file;
+ int index;
+
+ if ((def == NULL) || (ident == NULL) || (args == NULL))
+ return (EINVAL);
+
+ file = ident_to_file (ident);
+ if (file == NULL)
+ {
+ DEBUG ("gl_ident_get_rrdargs: ident_to_file returned NULL.\n");
+ return (-1);
+ }
+
+ DEBUG ("gl_ident_get_rrdargs: file = %s;\n", file);
+
+ index = array_argc (args);
+
+ /* CDEFs */
+ array_append_format (args, "DEF:def_%04i_min=%s:%s:MIN",
+ index, file, def->ds_name);
+ array_append_format (args, "DEF:def_%04i_avg=%s:%s:AVERAGE",
+ index, file, def->ds_name);
+ array_append_format (args, "DEF:def_%04i_max=%s:%s:MAX",
+ index, file, def->ds_name);
+ /* VDEFs */
+ array_append_format (args, "VDEF:vdef_%04i_min=def_%04i_min,MINIMUM",
+ index, index);
+ array_append_format (args, "VDEF:vdef_%04i_avg=def_%04i_avg,AVERAGE",
+ index, index);
+ array_append_format (args, "VDEF:vdef_%04i_max=def_%04i_max,MAXIMUM",
+ index, index);
+ array_append_format (args, "VDEF:vdef_%04i_lst=def_%04i_avg,LAST",
+ index, index);
+
+ /* Graph part */
+ array_append_format (args, "%s:def_%04i_avg#%06"PRIx32":%s%s",
+ def->area ? "AREA" : "LINE1",
+ index, def->color,
+ (def->legend != NULL) ? def->legend : def->ds_name,
+ def->stack ? ":STACK" : "");
+ array_append_format (args, "GPRINT:vdef_%04i_min:%s min,",
+ index, (def->format != NULL) ? def->format : "%lg");
+ array_append_format (args, "GPRINT:vdef_%04i_avg:%s avg,",
+ index, (def->format != NULL) ? def->format : "%lg");
+ array_append_format (args, "GPRINT:vdef_%04i_max:%s max,",
+ index, (def->format != NULL) ? def->format : "%lg");
+ array_append_format (args, "GPRINT:vdef_%04i_lst:%s last\\l",
+ index, (def->format != NULL) ? def->format : "%lg");
+
+ free (file);
+
+ return (0);
+} /* }}} int def_get_rrdargs */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/graph_def.h b/src/graph_def.h
--- /dev/null
+++ b/src/graph_def.h
@@ -0,0 +1,35 @@
+#ifndef GRAPH_DEF_H
+#define GRAPH_DEF_H 1
+
+struct graph_def_s;
+typedef struct graph_def_s graph_def_t;
+
+typedef int (*def_callback_t) (graph_def_t *def,
+ void *user_data);
+
+#include "graph.h"
+#include "graph_ident.h"
+#include "utils_array.h"
+#include "oconfig.h"
+
+graph_def_t *def_create (graph_config_t *cfg, graph_ident_t *ident,
+ const char *ds_name);
+
+void def_destroy (graph_def_t *def);
+
+int def_config (graph_config_t *cfg, const oconfig_item_t *ci);
+
+int def_append (graph_def_t *head, graph_def_t *def);
+
+graph_def_t *def_search (graph_def_t *head, graph_ident_t *ident,
+ const char *ds_name);
+
+_Bool def_matches (graph_def_t *def, graph_ident_t *ident);
+
+int def_foreach (graph_def_t *def, def_callback_t callback, void *user_data);
+
+int def_get_rrdargs (graph_def_t *def, graph_ident_t *ident,
+ str_array_t *args);
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
+#endif
diff --git a/src/graph_ident.c b/src/graph_ident.c
--- /dev/null
+++ b/src/graph_ident.c
@@ -0,0 +1,455 @@
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <limits.h> /* PATH_MAX */
+
+#include "graph_ident.h"
+#include "common.h"
+#include "filesystem.h"
+
+/*
+ * Data types
+ */
+struct graph_ident_s /* {{{ */
+{
+ char *host;
+ char *plugin;
+ char *plugin_instance;
+ char *type;
+ char *type_instance;
+}; /* }}} struct graph_ident_s */
+
+/*
+ * Private functions
+ */
+static char *part_copy_with_selector (const char *selector, /* {{{ */
+ const char *part, unsigned int flags)
+{
+ if ((selector == NULL) || (part == NULL))
+ return (NULL);
+
+ if ((flags & IDENT_FLAG_REPLACE_ANY) && IS_ANY (part))
+ return (NULL);
+
+ if ((flags & IDENT_FLAG_REPLACE_ALL) && IS_ALL (part))
+ return (NULL);
+
+ /* Replace the ANY and ALL flags if requested and if the selecter actually
+ * *is* that flag. */
+ if (IS_ANY (selector))
+ {
+ if (flags & IDENT_FLAG_REPLACE_ANY)
+ return (strdup (part));
+ else
+ return (strdup (selector));
+ }
+
+ if (IS_ALL (selector))
+ {
+ if (flags & IDENT_FLAG_REPLACE_ALL)
+ return (strdup (part));
+ else
+ return (strdup (selector));
+ }
+
+ if (strcmp (selector, part) != 0)
+ return (NULL);
+
+ /* Otherwise (no replacement), return a copy of the selector. */
+ return (strdup (selector));
+} /* }}} char *part_copy_with_selector */
+
+static _Bool part_matches (const char *selector, /* {{{ */
+ const char *part)
+{
+ if ((selector == NULL) && (part == NULL))
+ return (1);
+
+ if (selector == NULL) /* && (part != NULL) */
+ return (0);
+
+ if (IS_ANY(selector) || IS_ALL(selector))
+ return (1);
+
+ if (part == NULL) /* && (selector != NULL) */
+ return (0);
+
+ if (strcmp (selector, part) == 0)
+ return (1);
+
+ return (0);
+} /* }}} _Bool part_matches */
+
+/*
+ * Public functions
+ */
+graph_ident_t *ident_create (const char *host, /* {{{ */
+ const char *plugin, const char *plugin_instance,
+ const char *type, const char *type_instance)
+{
+ graph_ident_t *ret;
+
+ if ((host == NULL)
+ || (plugin == NULL) || (plugin_instance == NULL)
+ || (type == NULL) || (type_instance == NULL))
+ return (NULL);
+
+ ret = malloc (sizeof (*ret));
+ if (ret == NULL)
+ return (NULL);
+ memset (ret, 0, sizeof (*ret));
+
+ ret->host = NULL;
+ ret->host = NULL;
+ ret->plugin = NULL;
+ ret->plugin_instance = NULL;
+ ret->type = NULL;
+ ret->type_instance = NULL;
+
+#define COPY_PART(p) do { \
+ ret->p = strdup (p); \
+ if (ret->p == NULL) \
+ { \
+ free (ret->host); \
+ free (ret->plugin); \
+ free (ret->plugin_instance); \
+ free (ret->type); \
+ free (ret->type_instance); \
+ free (ret); \
+ return (NULL); \
+ } \
+} while (0)
+
+ COPY_PART(host);
+ COPY_PART(plugin);
+ COPY_PART(plugin_instance);
+ COPY_PART(type);
+ COPY_PART(type_instance);
+
+#undef COPY_PART
+
+ return (ret);
+} /* }}} graph_ident_t *ident_create */
+
+graph_ident_t *ident_clone (const graph_ident_t *ident) /* {{{ */
+{
+ return (ident_create (ident->host,
+ ident->plugin, ident->plugin_instance,
+ ident->type, ident->type_instance));
+} /* }}} graph_ident_t *ident_clone */
+
+graph_ident_t *ident_copy_with_selector (const graph_ident_t *selector, /* {{{ */
+ const graph_ident_t *ident, unsigned int flags)
+{
+ graph_ident_t *ret;
+
+ if ((selector == NULL) || (ident == NULL))
+ return (NULL);
+
+ ret = malloc (sizeof (*ret));
+ if (ret == NULL)
+ return (NULL);
+ memset (ret, 0, sizeof (*ret));
+ ret->host = NULL;
+ ret->plugin = NULL;
+ ret->plugin_instance = NULL;
+ ret->type = NULL;
+ ret->type_instance = NULL;
+
+#define COPY_PART(p) do { \
+ ret->p = part_copy_with_selector (selector->p, ident->p, flags); \
+ if (ret->p == NULL) \
+ { \
+ free (ret->host); \
+ free (ret->plugin); \
+ free (ret->plugin_instance); \
+ free (ret->type); \
+ free (ret->type_instance); \
+ return (NULL); \
+ } \
+} while (0)
+
+ COPY_PART (host);
+ COPY_PART (plugin);
+ COPY_PART (plugin_instance);
+ COPY_PART (type);
+ COPY_PART (type_instance);
+
+#undef COPY_PART
+
+ return (ret);
+} /* }}} graph_ident_t *ident_copy_with_selector */
+
+void ident_destroy (graph_ident_t *ident) /* {{{ */
+{
+ if (ident == NULL)
+ return;
+
+ free (ident->host);
+ free (ident->plugin);
+ free (ident->plugin_instance);
+ free (ident->type);
+ free (ident->type_instance);
+
+ free (ident);
+} /* }}} void ident_destroy */
+
+/* ident_get_* methods {{{ */
+const char *ident_get_host (graph_ident_t *ident) /* {{{ */
+{
+ if (ident == NULL)
+ return (NULL);
+
+ return (ident->host);
+} /* }}} char *ident_get_host */
+
+const char *ident_get_plugin (graph_ident_t *ident) /* {{{ */
+{
+ if (ident == NULL)
+ return (NULL);
+
+ return (ident->plugin);
+} /* }}} char *ident_get_plugin */
+
+const char *ident_get_plugin_instance (graph_ident_t *ident) /* {{{ */
+{
+ if (ident == NULL)
+ return (NULL);
+
+ return (ident->plugin_instance);
+} /* }}} char *ident_get_plugin_instance */
+
+const char *ident_get_type (graph_ident_t *ident) /* {{{ */
+{
+ if (ident == NULL)
+ return (NULL);
+
+ return (ident->type);
+} /* }}} char *ident_get_type */
+
+const char *ident_get_type_instance (graph_ident_t *ident) /* {{{ */
+{
+ if (ident == NULL)
+ return (NULL);
+
+ return (ident->type_instance);
+} /* }}} char *ident_get_type_instance */
+/* }}} ident_get_* methods */
+
+/* ident_set_* methods {{{ */
+int ident_set_host (graph_ident_t *ident, const char *host) /* {{{ */
+{
+ char *tmp;
+
+ if ((ident == NULL) || (host == NULL))
+ return (EINVAL);
+
+ tmp = strdup (host);
+ if (tmp == NULL)
+ return (ENOMEM);
+
+ free (ident->host);
+ ident->host = tmp;
+
+ return (0);
+} /* }}} int ident_set_host */
+
+int ident_set_plugin (graph_ident_t *ident, const char *plugin) /* {{{ */
+{
+ char *tmp;
+
+ if ((ident == NULL) || (plugin == NULL))
+ return (EINVAL);
+
+ tmp = strdup (plugin);
+ if (tmp == NULL)
+ return (ENOMEM);
+
+ free (ident->plugin);
+ ident->plugin = tmp;
+
+ return (0);
+} /* }}} int ident_set_plugin */
+
+int ident_set_plugin_instance (graph_ident_t *ident, const char *plugin_instance) /* {{{ */
+{
+ char *tmp;
+
+ if ((ident == NULL) || (plugin_instance == NULL))
+ return (EINVAL);
+
+ tmp = strdup (plugin_instance);
+ if (tmp == NULL)
+ return (ENOMEM);
+
+ free (ident->plugin_instance);
+ ident->plugin_instance = tmp;
+
+ return (0);
+} /* }}} int ident_set_plugin_instance */
+
+int ident_set_type (graph_ident_t *ident, const char *type) /* {{{ */
+{
+ char *tmp;
+
+ if ((ident == NULL) || (type == NULL))
+ return (EINVAL);
+
+ tmp = strdup (type);
+ if (tmp == NULL)
+ return (ENOMEM);
+
+ free (ident->type);
+ ident->type = tmp;
+
+ return (0);
+} /* }}} int ident_set_type */
+
+int ident_set_type_instance (graph_ident_t *ident, const char *type_instance) /* {{{ */
+{
+ char *tmp;
+
+ if ((ident == NULL) || (type_instance == NULL))
+ return (EINVAL);
+
+ tmp = strdup (type_instance);
+ if (tmp == NULL)
+ return (ENOMEM);
+
+ free (ident->type_instance);
+ ident->type_instance = tmp;
+
+ return (0);
+} /* }}} int ident_set_type_instance */
+
+/* }}} ident_set_* methods */
+
+int ident_compare (const graph_ident_t *i0, /* {{{ */
+ const graph_ident_t *i1)
+{
+ int status;
+
+#define COMPARE_PART(p) do { \
+ status = strcmp (i0->p, i1->p); \
+ if (status != 0) \
+ return (status); \
+} while (0)
+
+ COMPARE_PART (host);
+ COMPARE_PART (plugin);
+ COMPARE_PART (plugin_instance);
+ COMPARE_PART (type);
+ COMPARE_PART (type_instance);
+
+#undef COMPARE_PART
+
+ return (0);
+} /* }}} int ident_compare */
+
+_Bool ident_matches (const graph_ident_t *selector, /* {{{ */
+ const graph_ident_t *ident)
+{
+ if ((selector == NULL) && (ident == NULL))
+ return (0);
+ else if (selector == NULL)
+ return (-1);
+ else if (ident == NULL)
+ return (1);
+
+ if (!part_matches (selector->host, ident->host))
+ return (0);
+
+ if (!part_matches (selector->plugin, ident->plugin))
+ return (0);
+
+ if (!part_matches (selector->plugin_instance, ident->plugin_instance))
+ return (0);
+
+ if (!part_matches (selector->type, ident->type))
+ return (0);
+
+ if (!part_matches (selector->type_instance, ident->type_instance))
+ return (0);
+
+ return (1);
+} /* }}} _Bool ident_matches */
+
+char *ident_to_string (const graph_ident_t *ident) /* {{{ */
+{
+ char buffer[PATH_MAX];
+
+ buffer[0] = 0;
+
+ strlcat (buffer, ident->host, sizeof (buffer));
+ strlcat (buffer, "/", sizeof (buffer));
+ strlcat (buffer, ident->plugin, sizeof (buffer));
+ if (ident->plugin_instance[0] != 0)
+ {
+ strlcat (buffer, "-", sizeof (buffer));
+ strlcat (buffer, ident->plugin_instance, sizeof (buffer));
+ }
+ strlcat (buffer, "/", sizeof (buffer));
+ strlcat (buffer, ident->type, sizeof (buffer));
+ if (ident->type_instance[0] != 0)
+ {
+ strlcat (buffer, "-", sizeof (buffer));
+ strlcat (buffer, ident->type_instance, sizeof (buffer));
+ }
+
+ return (strdup (buffer));
+} /* }}} char *ident_to_string */
+
+char *ident_to_file (const graph_ident_t *ident) /* {{{ */
+{
+ char buffer[PATH_MAX];
+
+ buffer[0] = 0;
+
+ strlcat (buffer, DATA_DIR, sizeof (buffer));
+ strlcat (buffer, "/", sizeof (buffer));
+
+ strlcat (buffer, ident->host, sizeof (buffer));
+ strlcat (buffer, "/", sizeof (buffer));
+ strlcat (buffer, ident->plugin, sizeof (buffer));
+ if (ident->plugin_instance[0] != 0)
+ {
+ strlcat (buffer, "-", sizeof (buffer));
+ strlcat (buffer, ident->plugin_instance, sizeof (buffer));
+ }
+ strlcat (buffer, "/", sizeof (buffer));
+ strlcat (buffer, ident->type, sizeof (buffer));
+ if (ident->type_instance[0] != 0)
+ {
+ strlcat (buffer, "-", sizeof (buffer));
+ strlcat (buffer, ident->type_instance, sizeof (buffer));
+ }
+
+ strlcat (buffer, ".rrd", sizeof (buffer));
+
+ return (strdup (buffer));
+} /* }}} char *ident_to_file */
+
+char *ident_to_json (const graph_ident_t *ident) /* {{{ */
+{
+ char buffer[4096];
+
+ buffer[0] = 0;
+
+ strlcat (buffer, "{\"host\":\"", sizeof (buffer));
+ strlcat (buffer, ident->host, sizeof (buffer));
+ strlcat (buffer, "\",\"plugin\":\"", sizeof (buffer));
+ strlcat (buffer, ident->plugin, sizeof (buffer));
+ strlcat (buffer, "\",\"plugin_instance\":\"", sizeof (buffer));
+ strlcat (buffer, ident->plugin_instance, sizeof (buffer));
+ strlcat (buffer, "\",\"type\":\"", sizeof (buffer));
+ strlcat (buffer, ident->type, sizeof (buffer));
+ strlcat (buffer, "\",\"type_instance\":\"", sizeof (buffer));
+ strlcat (buffer, ident->type_instance, sizeof (buffer));
+ strlcat (buffer, "\"}", sizeof (buffer));
+
+ return (strdup (buffer));
+} /* }}} char *ident_to_json */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
+
diff --git a/src/graph_ident.h b/src/graph_ident.h
--- /dev/null
+++ b/src/graph_ident.h
@@ -0,0 +1,50 @@
+#ifndef GRAPH_IDENT_H
+#define GRAPH_IDENT_H 1
+
+#define ANY_TOKEN "/any/"
+#define ALL_TOKEN "/all/"
+
+#define IS_ANY(str) (((str) != NULL) && (strcasecmp (ANY_TOKEN, (str)) == 0))
+#define IS_ALL(str) (((str) != NULL) && (strcasecmp (ALL_TOKEN, (str)) == 0))
+
+struct graph_ident_s;
+typedef struct graph_ident_s graph_ident_t;
+
+graph_ident_t *ident_create (const char *host,
+ const char *plugin, const char *plugin_instance,
+ const char *type, const char *type_instance);
+graph_ident_t *ident_clone (const graph_ident_t *ident);
+
+#define IDENT_FLAG_REPLACE_ALL 0x01
+#define IDENT_FLAG_REPLACE_ANY 0x02
+graph_ident_t *ident_copy_with_selector (const graph_ident_t *selector,
+ const graph_ident_t *ident, unsigned int flags);
+
+void ident_destroy (graph_ident_t *ident);
+
+const char *ident_get_host (graph_ident_t *ident);
+const char *ident_get_plugin (graph_ident_t *ident);
+const char *ident_get_plugin_instance (graph_ident_t *ident);
+const char *ident_get_type (graph_ident_t *ident);
+const char *ident_get_type_instance (graph_ident_t *ident);
+
+int ident_set_host (graph_ident_t *ident, const char *host);
+int ident_set_plugin (graph_ident_t *ident, const char *plugin);
+int ident_set_plugin_instance (graph_ident_t *ident,
+ const char *plugin_instance);
+int ident_set_type (graph_ident_t *ident, const char *type);
+int ident_set_type_instance (graph_ident_t *ident,
+ const char *type_instance);
+
+int ident_compare (const graph_ident_t *i0,
+ const graph_ident_t *i1);
+
+_Bool ident_matches (const graph_ident_t *selector,
+ const graph_ident_t *ident);
+
+char *ident_to_string (const graph_ident_t *ident);
+char *ident_to_file (const graph_ident_t *ident);
+char *ident_to_json (const graph_ident_t *ident);
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
+#endif /* GRAPH_IDENT_H */
diff --git a/src/graph_instance.c b/src/graph_instance.c
--- /dev/null
+++ b/src/graph_instance.c
@@ -0,0 +1,475 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "graph_instance.h"
+#include "graph_ident.h"
+#include "graph_list.h"
+#include "common.h"
+#include "utils_params.h"
+
+#include <fcgiapp.h>
+#include <fcgi_stdio.h>
+
+struct graph_instance_s /* {{{ */
+{
+ graph_ident_t *select;
+
+ graph_ident_t **files;
+ size_t files_num;
+
+ graph_instance_t *next;
+}; /* }}} struct graph_instance_s */
+
+struct def_callback_data_s
+{
+ graph_instance_t *inst;
+ str_array_t *args;
+};
+typedef struct def_callback_data_s def_callback_data_t;
+
+/*
+ * Private functions
+ */
+/* Create one DEF for each data source in the file. Called by
+ * "inst_get_default_defs" for each file. */
+static graph_def_t *ident_get_default_defs (graph_config_t *cfg, /* {{{ */
+ graph_ident_t *ident, graph_def_t *def_head)
+{
+ graph_def_t *defs = NULL;
+ char *file;
+ char **dses = NULL;
+ size_t dses_num = 0;
+ int status;
+ size_t i;
+
+ if ((cfg == NULL) || (ident == NULL))
+ return (def_head);
+
+ file = ident_to_file (ident);
+ if (file == NULL)
+ {
+ fprintf (stderr, "ident_get_default_defs: ident_to_file failed\n");
+ return (def_head);
+ }
+
+ status = ds_list_from_rrd_file (file, &dses_num, &dses);
+ if (status != 0)
+ {
+ free (file);
+ return (def_head);
+ }
+
+ for (i = 0; i < dses_num; i++)
+ {
+ graph_def_t *def;
+
+ def = def_search (def_head, ident, dses[i]);
+ if (def != NULL)
+ continue;
+
+ def = def_create (cfg, ident, dses[i]);
+ if (def == NULL)
+ continue;
+
+ if (defs == NULL)
+ defs = def;
+ else
+ def_append (defs, def);
+
+ free (dses[i]);
+ }
+
+ free (dses);
+ free (file);
+
+ return (defs);
+} /* }}} int ident_get_default_defs */
+
+/* Create one or more DEFs for each file in the graph instance. The number
+ * depends on the number of data sources in each of the files. Called from
+ * "inst_get_rrdargs" if no DEFs are available from the configuration.
+ * */
+static graph_def_t *inst_get_default_defs (graph_config_t *cfg, /* {{{ */
+ graph_instance_t *inst)
+{
+ graph_def_t *defs = NULL;
+ size_t i;
+
+ if ((cfg == NULL) || (inst == NULL))
+ return (NULL);
+
+ for (i = 0; i < inst->files_num; i++)
+ {
+ graph_def_t *def;
+
+ def = ident_get_default_defs (cfg, inst->files[i], defs);
+ if (def == NULL)
+ continue;
+
+ if (defs == NULL)
+ defs = def;
+ else
+ def_append (defs, def);
+ }
+
+ return (defs);
+} /* }}} graph_def_t *inst_get_default_defs */
+
+/* Called with each DEF in turn. Calls "def_get_rrdargs" with every appropriate
+ * file / DEF pair. */
+static int gl_instance_get_rrdargs_cb (graph_def_t *def, void *user_data) /* {{{ */
+{
+ def_callback_data_t *data = user_data;
+ graph_instance_t *inst = data->inst;
+ str_array_t *args = data->args;
+
+ size_t i;
+
+ for (i = 0; i < inst->files_num; i++)
+ {
+ if (!def_matches (def, inst->files[i]))
+ continue;
+
+ def_get_rrdargs (def, inst->files[i], args);
+ }
+
+ return (0);
+} /* }}} int gl_instance_get_rrdargs_cb */
+
+static const char *get_part_from_param (const char *prim_key, /* {{{ */
+ const char *sec_key)
+{
+ const char *val;
+
+ val = param (prim_key);
+ if (val != NULL)
+ return (val);
+
+ return (param (sec_key));
+} /* }}} const char *get_part_from_param */
+
+/*
+ * Public functions
+ */
+graph_instance_t *inst_create (graph_config_t *cfg, /* {{{ */
+ const graph_ident_t *ident)
+{
+ graph_instance_t *i;
+ graph_ident_t *selector;
+
+ if ((cfg == NULL) || (ident == NULL))
+ return (NULL);
+
+ i = malloc (sizeof (*i));
+ if (i == NULL)
+ return (NULL);
+ memset (i, 0, sizeof (*i));
+
+ selector = graph_get_selector (cfg);
+ if (selector == NULL)
+ {
+ fprintf (stderr, "inst_create: graph_get_selector failed\n");
+ free (i);
+ return (NULL);
+ }
+
+ i->select = ident_copy_with_selector (selector, ident,
+ IDENT_FLAG_REPLACE_ANY);
+ if (i->select == NULL)
+ {
+ fprintf (stderr, "inst_create: ident_copy_with_selector failed\n");
+ ident_destroy (selector);
+ free (i);
+ return (NULL);
+ }
+
+ ident_destroy (selector);
+
+ i->files = NULL;
+ i->files_num = 0;
+
+ i->next = NULL;
+
+ return (i);
+} /* }}} graph_instance_t *inst_create */
+
+void inst_destroy (graph_instance_t *inst) /* {{{ */
+{
+ graph_instance_t *next;
+ size_t i;
+
+ if (inst == NULL)
+ return;
+
+ next = inst->next;
+
+ ident_destroy (inst->select);
+
+ for (i = 0; i < inst->files_num; i++)
+ ident_destroy (inst->files[i]);
+ free (inst->files);
+
+ free (inst);
+
+ inst_destroy (next);
+} /* }}} void inst_destroy */
+
+int inst_add_file (graph_instance_t *inst, /* {{{ */
+ const graph_ident_t *file)
+{
+ graph_ident_t **tmp;
+
+ tmp = realloc (inst->files, sizeof (*inst->files) * (inst->files_num + 1));
+ if (tmp == NULL)
+ return (ENOMEM);
+ inst->files = tmp;
+
+ inst->files[inst->files_num] = ident_clone (file);
+ if (inst->files[inst->files_num] == NULL)
+ return (ENOMEM);
+
+ inst->files_num++;
+
+ return (0);
+} /* }}} int inst_add_file */
+
+graph_instance_t *inst_get_selected (graph_config_t *cfg) /* {{{ */
+{
+ const char *host = get_part_from_param ("inst_host", "host");
+ const char *plugin = get_part_from_param ("inst_plugin", "plugin");
+ const char *plugin_instance = get_part_from_param ("inst_plugin_instance", "plugin_instance");
+ const char *type = get_part_from_param ("inst_type", "type");
+ const char *type_instance = get_part_from_param ("inst_type_instance", "type_instance");
+ graph_ident_t *ident;
+ graph_instance_t *inst;
+
+ if (cfg == NULL)
+ cfg = gl_graph_get_selected ();
+
+ if (cfg == NULL)
+ {
+ DEBUG ("inst_get_selected: cfg == NULL;\n");
+ return (NULL);
+ }
+
+ if ((host == NULL)
+ || (plugin == NULL) || (plugin_instance == NULL)
+ || (type == NULL) || (type_instance == NULL))
+ {
+ DEBUG ("inst_get_selected: A parameter is NULL.\n");
+ return (NULL);
+ }
+
+ ident = ident_create (host, plugin, plugin_instance, type, type_instance);
+
+ for (inst = graph_get_instances (cfg); inst != NULL; inst = inst->next)
+ {
+ if (ident_compare (ident, inst->select) != 0)
+ continue;
+
+ ident_destroy (ident);
+ return (inst);
+ }
+
+ DEBUG ("inst_get_selected: No match found.\n");
+ ident_destroy (ident);
+ return (NULL);
+} /* }}} graph_instance_t *inst_get_selected */
+
+int inst_get_rrdargs (graph_config_t *cfg, /* {{{ */
+ graph_instance_t *inst,
+ str_array_t *args)
+{
+ def_callback_data_t data = { inst, args };
+ graph_def_t *defs;
+ int status;
+
+ if ((cfg == NULL) || (inst == NULL) || (args == NULL))
+ return (EINVAL);
+
+ status = graph_get_rrdargs (cfg, inst, args);
+ if (status != 0)
+ return (status);
+
+ defs = graph_get_defs (cfg);
+ if (defs == NULL)
+ {
+ defs = inst_get_default_defs (cfg, inst);
+
+ if (defs == NULL)
+ return (-1);
+
+ status = def_foreach (defs, gl_instance_get_rrdargs_cb, &data);
+
+ def_destroy (defs);
+ }
+ else
+ {
+ status = def_foreach (defs, gl_instance_get_rrdargs_cb, &data);
+ }
+
+ return (status);
+} /* }}} int inst_get_rrdargs */
+
+graph_ident_t *inst_get_selector (graph_instance_t *inst) /* {{{ */
+{
+ if (inst == NULL)
+ return (NULL);
+
+ return (ident_clone (inst->select));
+} /* }}} graph_ident_t *inst_get_selector */
+
+int inst_get_params (graph_config_t *cfg, graph_instance_t *inst, /* {{{ */
+ char *buffer, size_t buffer_size)
+{
+ graph_ident_t *cfg_select;
+
+ if ((cfg == NULL) || (inst == NULL)
+ || (buffer == NULL) || (buffer_size < 1))
+ return (EINVAL);
+
+ cfg_select = graph_get_selector (cfg);
+ if (cfg_select == NULL)
+ {
+ fprintf (stderr, "inst_get_params: graph_get_selector failed");
+ return (-1);
+ }
+
+ buffer[0] = 0;
+
+#define COPY_FIELD(field) do { \
+ const char *cfg_f = ident_get_##field (cfg_select); \
+ const char *inst_f = ident_get_##field (inst->select); \
+ if (strcmp (cfg_f, inst_f) == 0) \
+ { \
+ strlcat (buffer, #field, buffer_size); \
+ strlcat (buffer, "=", buffer_size); \
+ strlcat (buffer, cfg_f, buffer_size); \
+ } \
+ else \
+ { \
+ strlcat (buffer, "graph_", buffer_size); \
+ strlcat (buffer, #field, buffer_size); \
+ strlcat (buffer, "=", buffer_size); \
+ strlcat (buffer, cfg_f, buffer_size); \
+ strlcat (buffer, ";", buffer_size); \
+ strlcat (buffer, "inst_", buffer_size); \
+ strlcat (buffer, #field, buffer_size); \
+ strlcat (buffer, "=", buffer_size); \
+ strlcat (buffer, inst_f, buffer_size); \
+ } \
+} while (0)
+
+ COPY_FIELD(host);
+ strlcat (buffer, ";", buffer_size);
+ COPY_FIELD(plugin);
+ strlcat (buffer, ";", buffer_size);
+ COPY_FIELD(plugin_instance);
+ strlcat (buffer, ";", buffer_size);
+ COPY_FIELD(type);
+ strlcat (buffer, ";", buffer_size);
+ COPY_FIELD(type_instance);
+
+#undef COPY_FIELD
+
+ ident_destroy (cfg_select);
+
+ return (0);
+} /* }}} int inst_get_params */
+
+int inst_append (graph_instance_t *head, graph_instance_t *inst) /* {{{ */
+{
+ graph_instance_t *ptr;
+
+ if ((head == NULL) || (inst == NULL))
+ return (EINVAL);
+
+ ptr = head;
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = inst;
+
+ return (0);
+} /* }}} int inst_append */
+
+int inst_foreach (graph_instance_t *inst, /* {{{ */
+ inst_callback_t cb, void *user_data)
+{
+ graph_instance_t *ptr;
+
+ if ((inst == NULL) || (cb == NULL))
+ return (EINVAL);
+
+ for (ptr = inst; ptr != NULL; ptr = ptr->next)
+ {
+ int status;
+
+ status = (*cb) (ptr, user_data);
+ if (status != 0)
+ return (status);
+ }
+
+ return (0);
+} /* }}} int inst_foreach */
+
+graph_instance_t *inst_find_matching (graph_instance_t *inst, /* {{{ */
+ const graph_ident_t *ident)
+{
+ graph_instance_t *ptr;
+
+ if ((inst == NULL) || (ident == NULL))
+ return (NULL);
+
+ for (ptr = inst; ptr != NULL; ptr = ptr->next)
+ if (ident_matches (ptr->select, ident))
+ return (ptr);
+
+ return (NULL);
+} /* }}} graph_instance_t *inst_find_matching */
+
+int inst_describe (graph_config_t *cfg, graph_instance_t *inst, /* {{{ */
+ char *buffer, size_t buffer_size)
+{
+ graph_ident_t *cfg_select;
+
+ if ((cfg == NULL) || (inst == NULL)
+ || (buffer == NULL) || (buffer_size < 2))
+ return (EINVAL);
+
+ cfg_select = graph_get_selector (cfg);
+ if (cfg_select == NULL)
+ {
+ fprintf (stderr, "inst_describe: graph_get_selector failed\n");
+ return (-1);
+ }
+
+ buffer[0] = 0;
+
+#define CHECK_FIELD(field) do { \
+ if (IS_ANY (ident_get_##field (cfg_select))) \
+ { \
+ if (buffer[0] != 0) \
+ strlcat (buffer, "/", buffer_size); \
+ strlcat (buffer, ident_get_##field (inst->select), buffer_size); \
+ } \
+} while (0)
+
+ CHECK_FIELD (host);
+ CHECK_FIELD (plugin);
+ CHECK_FIELD (plugin_instance);
+ CHECK_FIELD (type);
+ CHECK_FIELD (type_instance);
+
+#undef CHECK_FIELD
+
+ if (buffer[0] == 0)
+ strlcat (buffer, "default", buffer_size);
+
+ ident_destroy (cfg_select);
+
+ return (0);
+} /* }}} int inst_describe */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/graph_instance.h b/src/graph_instance.h
--- /dev/null
+++ b/src/graph_instance.h
@@ -0,0 +1,50 @@
+#ifndef GRAPH_INSTANCE_H
+#define GRAPH_INSTANCE_H 1
+
+/*
+ * Data types
+ */
+struct graph_instance_s;
+typedef struct graph_instance_s graph_instance_t;
+
+typedef int (*inst_callback_t) (graph_instance_t *inst, void *user_data);
+
+#include "graph.h"
+#include "utils_array.h"
+
+/*
+ * Callback types
+ */
+/*
+ * Methods
+ */
+graph_instance_t *inst_create (graph_config_t *cfg,
+ const graph_ident_t *ident);
+
+void inst_destroy (graph_instance_t *inst);
+
+int inst_add_file (graph_instance_t *inst, const graph_ident_t *file);
+
+graph_instance_t *inst_get_selected (graph_config_t *cfg);
+
+int inst_get_params (graph_config_t *cfg, graph_instance_t *inst,
+ char *buffer, size_t buffer_size);
+
+int inst_get_rrdargs (graph_config_t *cfg, graph_instance_t *inst,
+ str_array_t *args);
+
+graph_ident_t *inst_get_selector (graph_instance_t *inst);
+
+int inst_append (graph_instance_t *head, graph_instance_t *inst);
+
+int inst_foreach (graph_instance_t *inst,
+ inst_callback_t cb, void *user_data);
+
+graph_instance_t *inst_find_matching (graph_instance_t *inst,
+ const graph_ident_t *ident);
+
+int inst_describe (graph_config_t *cfg, graph_instance_t *inst,
+ char *buffer, size_t buffer_size);
+
+#endif /* GRAPH_INSTANCE_H */
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/graph_list.c b/src/graph_list.c
--- /dev/null
+++ b/src/graph_list.c
@@ -0,0 +1,287 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include "graph_list.h"
+#include "graph_ident.h"
+#include "graph_def.h"
+#include "graph_config.h"
+#include "common.h"
+#include "filesystem.h"
+#include "utils_params.h"
+
+#include <fcgiapp.h>
+#include <fcgi_stdio.h>
+
+/*
+ * Defines
+ */
+#define UPDATE_INTERVAL 10
+
+/*
+ * Global variables
+ */
+static graph_config_t **gl_active = NULL;
+static size_t gl_active_num = 0;
+
+static graph_config_t **gl_staging = NULL;
+static size_t gl_staging_num = 0;
+
+static time_t gl_last_update = 0;
+
+/*
+ * Private functions
+ */
+int gl_add_graph_internal (graph_config_t *cfg, /* {{{ */
+ graph_config_t ***gl_array, size_t *gl_array_num)
+{
+ graph_config_t **tmp;
+
+#define ARRAY_PTR (*gl_array)
+#define ARRAY_SIZE (*gl_array_num)
+
+ if (cfg == NULL)
+ return (EINVAL);
+
+ tmp = realloc (ARRAY_PTR, sizeof (*ARRAY_PTR) * (ARRAY_SIZE + 1));
+ if (tmp == NULL)
+ return (ENOMEM);
+ ARRAY_PTR = tmp;
+
+ ARRAY_PTR[ARRAY_SIZE] = cfg;
+ ARRAY_SIZE++;
+
+#undef ARRAY_SIZE
+#undef ARRAY_PTR
+
+ return (0);
+} /* }}} int gl_add_graph_internal */
+
+static int gl_register_file (const graph_ident_t *file, /* {{{ */
+ __attribute__((unused)) void *user_data)
+{
+ graph_config_t *cfg;
+ int num_graphs = 0;
+ size_t i;
+
+ for (i = 0; i < gl_active_num; i++)
+ {
+ graph_config_t *cfg = gl_active[i];
+ int status;
+
+ if (!graph_matches (cfg, file))
+ continue;
+
+ status = graph_add_file (cfg, file);
+ if (status != 0)
+ {
+ /* report error */;
+ }
+ else
+ {
+ num_graphs++;
+ }
+ }
+
+ if (num_graphs == 0)
+ {
+ cfg = graph_create (file);
+ gl_add_graph_internal (cfg, &gl_active, &gl_active_num);
+ graph_add_file (cfg, file);
+ }
+
+ return (0);
+} /* }}} int gl_register_file */
+
+static const char *get_part_from_param (const char *prim_key, /* {{{ */
+ const char *sec_key)
+{
+ const char *val;
+
+ val = param (prim_key);
+ if (val != NULL)
+ return (val);
+
+ return (param (sec_key));
+} /* }}} const char *get_part_from_param */
+
+static int gl_clear_instances (void) /* {{{ */
+{
+ size_t i;
+
+ for (i = 0; i < gl_active_num; i++)
+ graph_clear_instances (gl_active[i]);
+
+ return (0);
+} /* }}} int gl_clear_instances */
+
+
+/*
+ * Global functions
+ */
+int gl_add_graph (graph_config_t *cfg) /* {{{ */
+{
+ return (gl_add_graph_internal (cfg, &gl_staging, &gl_staging_num));
+} /* }}} int gl_add_graph */
+
+int gl_config_submit (void) /* {{{ */
+{
+ graph_config_t **old;
+ size_t old_num;
+ size_t i;
+
+ old = gl_active;
+ old_num = gl_active_num;
+
+ gl_active = gl_staging;
+ gl_active_num = gl_staging_num;
+
+ gl_staging = NULL;
+ gl_staging_num = 0;
+
+ for (i = 0; i < old_num; i++)
+ {
+ graph_destroy (old[i]);
+ old[i] = NULL;
+ }
+ free (old);
+
+ return (0);
+} /* }}} int graph_config_submit */
+
+int gl_graph_get_all (gl_cfg_callback callback, /* {{{ */
+ void *user_data)
+{
+ size_t i;
+
+ if (callback == NULL)
+ return (EINVAL);
+
+ gl_update ();
+
+ for (i = 0; i < gl_active_num; i++)
+ {
+ int status;
+
+ status = (*callback) (gl_active[i], user_data);
+ if (status != 0)
+ return (status);
+ }
+
+ return (0);
+} /* }}} int gl_graph_get_all */
+
+graph_config_t *gl_graph_get_selected (void) /* {{{ */
+{
+ const char *host = get_part_from_param ("graph_host", "host");
+ const char *plugin = get_part_from_param ("graph_plugin", "plugin");
+ const char *plugin_instance = get_part_from_param ("graph_plugin_instance", "plugin_instance");
+ const char *type = get_part_from_param ("graph_type", "type");
+ const char *type_instance = get_part_from_param ("graph_type_instance", "type_instance");
+ graph_ident_t *ident;
+ size_t i;
+
+ if ((host == NULL)
+ || (plugin == NULL) || (plugin_instance == NULL)
+ || (type == NULL) || (type_instance == NULL))
+ return (NULL);
+
+ ident = ident_create (host, plugin, plugin_instance, type, type_instance);
+
+ gl_update ();
+
+ for (i = 0; i < gl_active_num; i++)
+ {
+ if (graph_compare (gl_active[i], ident) != 0)
+ continue;
+
+ ident_destroy (ident);
+ return (gl_active[i]);
+ }
+
+ ident_destroy (ident);
+ return (NULL);
+} /* }}} graph_config_t *gl_graph_get_selected */
+
+/* gl_instance_get_all, gl_graph_instance_get_all {{{ */
+struct gl_inst_callback_data /* {{{ */
+{
+ graph_config_t *cfg;
+ gl_inst_callback callback;
+ void *user_data;
+}; /* }}} struct gl_inst_callback_data */
+
+static int gl_inst_callback_handler (graph_instance_t *inst, /* {{{ */
+ void *user_data)
+{
+ struct gl_inst_callback_data *data = user_data;
+
+ return ((*data->callback) (data->cfg, inst, data->user_data));
+} /* }}} int gl_inst_callback_handler */
+
+int gl_graph_instance_get_all (graph_config_t *cfg, /* {{{ */
+ gl_inst_callback callback, void *user_data)
+{
+ struct gl_inst_callback_data data =
+ {
+ cfg,
+ callback,
+ user_data
+ };
+
+ if ((cfg == NULL) || (callback == NULL))
+ return (EINVAL);
+
+ return (inst_foreach (graph_get_instances (cfg),
+ gl_inst_callback_handler, &data));
+} /* }}} int gl_graph_instance_get_all */
+
+int gl_instance_get_all (gl_inst_callback callback, /* {{{ */
+ void *user_data)
+{
+ size_t i;
+
+ gl_update ();
+
+ for (i = 0; i < gl_active_num; i++)
+ {
+ int status;
+
+ status = gl_graph_instance_get_all (gl_active[i], callback, user_data);
+ if (status != 0)
+ return (status);
+ }
+
+ return (0);
+} /* }}} int gl_instance_get_all */
+/* }}} gl_instance_get_all, gl_graph_instance_get_all */
+
+int gl_update (void) /* {{{ */
+{
+ time_t now;
+ int status;
+
+ /*
+ printf ("Content-Type: text/plain\n\n");
+ */
+
+ now = time (NULL);
+
+ if ((gl_last_update + UPDATE_INTERVAL) >= now)
+ return (0);
+
+ graph_read_config ();
+
+ gl_clear_instances ();
+ status = fs_scan (/* callback = */ gl_register_file, /* user data = */ NULL);
+
+ gl_last_update = now;
+
+ return (status);
+} /* }}} int gl_update */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/graph_list.h b/src/graph_list.h
--- /dev/null
+++ b/src/graph_list.h
@@ -0,0 +1,36 @@
+#ifndef GRAPH_LIST_H
+#define GRAPH_LIST_H 1
+
+#include "graph_instance.h"
+
+/*
+ * Callback types
+ */
+typedef int (*gl_cfg_callback) (graph_config_t *cfg,
+ void *user_data);
+
+typedef int (*gl_inst_callback) (graph_config_t *cfg,
+ graph_instance_t *inst, void *user_data);
+
+/*
+ * Functions
+ */
+int gl_add_graph (graph_config_t *cfg);
+
+int gl_config_submit (void);
+
+int gl_graph_get_all (gl_cfg_callback callback,
+ void *user_data);
+
+graph_config_t *gl_graph_get_selected (void);
+
+int gl_graph_instance_get_all (graph_config_t *cfg,
+ gl_inst_callback callback, void *user_data);
+
+int gl_instance_get_all (gl_inst_callback callback,
+ void *user_data);
+
+int gl_update (void);
+
+#endif /* GRAPH_LIST_H */
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/main.c b/src/main.c
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,112 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include "common.h"
+#include "graph_list.h"
+#include "utils_params.h"
+
+#include "action_graph.h"
+#include "action_list_graphs.h"
+
+/* Include this last, so the macro magic of <fcgi_stdio.h> doesn't interfere
+ * with our own header files. */
+#include <fcgiapp.h>
+#include <fcgi_stdio.h>
+
+struct action_s
+{
+ const char *name;
+ int (*callback) (void);
+};
+typedef struct action_s action_t;
+
+static int action_usage (void);
+
+static const action_t actions[] =
+{
+ { "graph", action_graph },
+ { "list_graphs", action_list_graphs },
+ { "usage", action_usage }
+};
+static const size_t actions_num = sizeof (actions) / sizeof (actions[0]);
+
+
+static int action_usage (void) /* {{{ */
+{
+ size_t i;
+
+ printf ("Content-Type: text/plain\n\n");
+
+ printf ("Usage:\n"
+ "\n"
+ " Available actions:\n"
+ "\n");
+
+ for (i = 0; i < actions_num; i++)
+ printf (" * %s\n", actions[i].name);
+
+ printf ("\n");
+
+ return (0);
+} /* }}} int action_usage */
+
+static int handle_request (void) /* {{{ */
+{
+ const char *action;
+
+ param_init ();
+
+ action = param ("action");
+ if (action == NULL)
+ {
+ return (action_usage ());
+ }
+ else
+ {
+ size_t i;
+
+ for (i = 0; i < actions_num; i++)
+ {
+ if (strcmp (action, actions[i].name) == 0)
+ return ((*actions[i].callback) ());
+ }
+
+ return (action_usage ());
+ }
+} /* }}} int handle_request */
+
+static int run (void) /* {{{ */
+{
+ while (FCGI_Accept() >= 0)
+ {
+ handle_request ();
+ param_finish ();
+ }
+
+ return (0);
+} /* }}} int run */
+
+int main (int argc, char **argv) /* {{{ */
+{
+ int status;
+
+ argc = 0;
+ argv = NULL;
+
+ if (FCGX_IsCGI ())
+ status = handle_request ();
+ else
+ status = run ();
+
+ exit ((status == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
+} /* }}} int main */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/oconfig.c b/src/oconfig.c
--- /dev/null
+++ b/src/oconfig.c
@@ -0,0 +1,218 @@
+/**
+ * oconfig - src/oconfig.c
+ * Copyright (C) 2006,2007 Florian octo Forster <octo at verplant.org>
+ *
+ * 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; only version 2 of the License is applicable.
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "oconfig.h"
+
+extern FILE *yyin;
+int yyparse (void);
+
+oconfig_item_t *ci_root;
+const char *c_file;
+
+static void yyset_in (FILE *fd)
+{
+ yyin = fd;
+} /* void yyset_in */
+
+oconfig_item_t *oconfig_parse_fh (FILE *fh)
+{
+ int status;
+ oconfig_item_t *ret;
+
+ char file[10];
+
+ yyset_in (fh);
+
+ if (NULL == c_file) {
+ int status;
+
+ status = snprintf (file, sizeof (file), "<fd#%d>", fileno (fh));
+
+ if ((status < 0) || (((size_t) status) >= sizeof (file))) {
+ c_file = "<unknown>";
+ }
+ else {
+ file[sizeof (file) - 1] = '\0';
+ c_file = file;
+ }
+ }
+
+ status = yyparse ();
+ if (status != 0)
+ {
+ fprintf (stderr, "yyparse returned error #%i\n", status);
+ return (NULL);
+ }
+
+ c_file = NULL;
+
+ ret = ci_root;
+ ci_root = NULL;
+ yyset_in ((FILE *) 0);
+
+ return (ret);
+} /* oconfig_item_t *oconfig_parse_fh */
+
+oconfig_item_t *oconfig_parse_file (const char *file)
+{
+ FILE *fh;
+ oconfig_item_t *ret;
+
+ c_file = file;
+
+ fh = fopen (file, "r");
+ if (fh == NULL)
+ {
+ fprintf (stderr, "fopen (%s) failed: %s\n", file, strerror (errno));
+ return (NULL);
+ }
+
+ ret = oconfig_parse_fh (fh);
+ fclose (fh);
+
+ c_file = NULL;
+
+ return (ret);
+} /* oconfig_item_t *oconfig_parse_file */
+
+oconfig_item_t *oconfig_clone (const oconfig_item_t *ci_orig)
+{
+ oconfig_item_t *ci_copy;
+
+ ci_copy = (oconfig_item_t *) malloc (sizeof (*ci_copy));
+ if (ci_copy == NULL)
+ {
+ fprintf (stderr, "malloc failed.\n");
+ return (NULL);
+ }
+ memset (ci_copy, 0, sizeof (*ci_copy));
+ ci_copy->values = NULL;
+ ci_copy->parent = NULL;
+ ci_copy->children = NULL;
+
+ ci_copy->key = strdup (ci_orig->key);
+ if (ci_copy->key == NULL)
+ {
+ fprintf (stderr, "strdup failed.\n");
+ free (ci_copy);
+ return (NULL);
+ }
+
+ if (ci_orig->values_num > 0) /* {{{ */
+ {
+ int i;
+
+ ci_copy->values = (oconfig_value_t *) calloc (ci_orig->values_num,
+ sizeof (*ci_copy->values));
+ if (ci_copy->values == NULL)
+ {
+ fprintf (stderr, "calloc failed.\n");
+ free (ci_copy->key);
+ free (ci_copy);
+ return (NULL);
+ }
+ ci_copy->values_num = ci_orig->values_num;
+
+ for (i = 0; i < ci_copy->values_num; i++)
+ {
+ ci_copy->values[i].type = ci_orig->values[i].type;
+ if (ci_copy->values[i].type == OCONFIG_TYPE_STRING)
+ {
+ ci_copy->values[i].value.string
+ = strdup (ci_orig->values[i].value.string);
+ if (ci_copy->values[i].value.string == NULL)
+ {
+ fprintf (stderr, "strdup failed.\n");
+ oconfig_free (ci_copy);
+ return (NULL);
+ }
+ }
+ else /* ci_copy->values[i].type != OCONFIG_TYPE_STRING) */
+ {
+ ci_copy->values[i].value = ci_orig->values[i].value;
+ }
+ }
+ } /* }}} if (ci_orig->values_num > 0) */
+
+ if (ci_orig->children_num > 0) /* {{{ */
+ {
+ int i;
+
+ ci_copy->children = (oconfig_item_t *) calloc (ci_orig->children_num,
+ sizeof (*ci_copy->children));
+ if (ci_copy->children == NULL)
+ {
+ fprintf (stderr, "calloc failed.\n");
+ oconfig_free (ci_copy);
+ return (NULL);
+ }
+ ci_copy->children_num = ci_orig->children_num;
+
+ for (i = 0; i < ci_copy->children_num; i++)
+ {
+ oconfig_item_t *child;
+
+ child = oconfig_clone (ci_orig->children + i);
+ if (child == NULL)
+ {
+ oconfig_free (ci_copy);
+ return (NULL);
+ }
+ child->parent = ci_copy;
+ ci_copy->children[i] = *child;
+ free (child);
+ } /* for (i = 0; i < ci_copy->children_num; i++) */
+ } /* }}} if (ci_orig->children_num > 0) */
+
+ return (ci_copy);
+} /* oconfig_item_t *oconfig_clone */
+
+void oconfig_free (oconfig_item_t *ci)
+{
+ int i;
+
+ if (ci == NULL)
+ return;
+
+ if (ci->key != NULL)
+ free (ci->key);
+
+ for (i = 0; i < ci->values_num; i++)
+ if ((ci->values[i].type == OCONFIG_TYPE_STRING)
+ && (NULL != ci->values[i].value.string))
+ free (ci->values[i].value.string);
+
+ if (ci->values != NULL)
+ free (ci->values);
+
+ for (i = 0; i < ci->children_num; i++)
+ oconfig_free (ci->children + i);
+
+ if (ci->children != NULL)
+ free (ci->children);
+}
+
+/*
+ * vim:shiftwidth=2:tabstop=8:softtabstop=2:fdm=marker
+ */
diff --git a/src/oconfig.h b/src/oconfig.h
--- /dev/null
+++ b/src/oconfig.h
@@ -0,0 +1,69 @@
+#ifndef OCONFIG_H
+#define OCONFIG_H 1
+
+#include <stdio.h>
+
+/**
+ * oconfig - src/oconfig.h
+ * Copyright (C) 2006-2009 Florian octo Forster <octo at verplant.org>
+ *
+ * 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; only version 2 of the License is applicable.
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * Types
+ */
+#define OCONFIG_TYPE_STRING 0
+#define OCONFIG_TYPE_NUMBER 1
+#define OCONFIG_TYPE_BOOLEAN 2
+
+struct oconfig_value_s
+{
+ union
+ {
+ char *string;
+ double number;
+ int boolean;
+ } value;
+ int type;
+};
+typedef struct oconfig_value_s oconfig_value_t;
+
+struct oconfig_item_s;
+typedef struct oconfig_item_s oconfig_item_t;
+struct oconfig_item_s
+{
+ char *key;
+ oconfig_value_t *values;
+ int values_num;
+
+ oconfig_item_t *parent;
+ oconfig_item_t *children;
+ int children_num;
+};
+
+/*
+ * Functions
+ */
+oconfig_item_t *oconfig_parse_fh (FILE *fh);
+oconfig_item_t *oconfig_parse_file (const char *file);
+
+oconfig_item_t *oconfig_clone (const oconfig_item_t *ci);
+
+void oconfig_free (oconfig_item_t *ci);
+
+/*
+ * vim: shiftwidth=2:tabstop=8:softtabstop=2
+ */
+#endif /* OCONFIG_H */
diff --git a/src/parser.y b/src/parser.y
--- /dev/null
+++ b/src/parser.y
@@ -0,0 +1,239 @@
+/**
+ * oconfig - src/parser.y
+ * Copyright (C) 2007,2008 Florian octo Forster <octo at verplant.org>
+ *
+ * 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; only version 2 of the License is applicable.
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+%{
+#include <stdlib.h>
+#include <string.h>
+#include "oconfig.h"
+#include "aux_types.h"
+
+static char *unquote (const char *orig);
+static int yyerror (const char *s);
+
+/* Lexer variables */
+extern int yylineno;
+extern char *yytext;
+
+extern oconfig_item_t *ci_root;
+extern char *c_file;
+%}
+
+%start entire_file
+
+%union {
+ double number;
+ int boolean;
+ char *string;
+ oconfig_value_t cv;
+ oconfig_item_t ci;
+ argument_list_t al;
+ statement_list_t sl;
+}
+
+%token <number> NUMBER
+%token <boolean> BTRUE BFALSE
+%token <string> QUOTED_STRING UNQUOTED_STRING
+%token SLASH OPENBRAC CLOSEBRAC EOL
+
+%type <string> string
+%type <string> identifier
+/* arguments */
+%type <cv> argument
+%type <al> argument_list
+/* blocks */
+%type <ci> block_begin
+%type <ci> block
+%type <string> block_end
+/* statements */
+%type <ci> option
+%type <ci> statement
+%type <sl> statement_list
+%type <ci> entire_file
+
+/* pass an verbose, specific error message to yyerror() */
+%error-verbose
+
+%%
+string:
+ QUOTED_STRING {$$ = unquote ($1);}
+ | UNQUOTED_STRING {$$ = strdup ($1);}
+ ;
+
+argument:
+ NUMBER {$$.value.number = $1; $$.type = OCONFIG_TYPE_NUMBER;}
+ | BTRUE {$$.value.boolean = 1; $$.type = OCONFIG_TYPE_BOOLEAN;}
+ | BFALSE {$$.value.boolean = 0; $$.type = OCONFIG_TYPE_BOOLEAN;}
+ | string {$$.value.string = $1; $$.type = OCONFIG_TYPE_STRING;}
+ ;
+
+argument_list:
+ argument_list argument
+ {
+ $$ = $1;
+ $$.argument_num++;
+ $$.argument = realloc ($$.argument, $$.argument_num * sizeof (oconfig_value_t));
+ $$.argument[$$.argument_num-1] = $2;
+ }
+ | argument
+ {
+ $$.argument = malloc (sizeof (oconfig_value_t));
+ $$.argument[0] = $1;
+ $$.argument_num = 1;
+ }
+ ;
+
+identifier:
+ UNQUOTED_STRING {$$ = strdup ($1);}
+ ;
+
+option:
+ identifier argument_list EOL
+ {
+ memset (&$$, '\0', sizeof ($$));
+ $$.key = $1;
+ $$.values = $2.argument;
+ $$.values_num = $2.argument_num;
+ }
+ ;
+
+block_begin:
+ OPENBRAC identifier CLOSEBRAC EOL
+ {
+ memset (&$$, '\0', sizeof ($$));
+ $$.key = $2;
+ }
+ |
+ OPENBRAC identifier argument_list CLOSEBRAC EOL
+ {
+ memset (&$$, '\0', sizeof ($$));
+ $$.key = $2;
+ $$.values = $3.argument;
+ $$.values_num = $3.argument_num;
+ }
+ ;
+
+block_end:
+ OPENBRAC SLASH identifier CLOSEBRAC EOL
+ {
+ $$ = $3;
+ }
+ ;
+
+block:
+ block_begin statement_list block_end
+ {
+ if (strcmp ($1.key, $3) != 0)
+ {
+ printf ("block_begin = %s; block_end = %s;\n", $1.key, $3);
+ yyerror ("Block not closed..\n");
+ exit (1);
+ }
+ free ($3); $3 = NULL;
+ $$ = $1;
+ $$.children = $2.statement;
+ $$.children_num = $2.statement_num;
+ }
+ ;
+
+statement:
+ option {$$ = $1;}
+ | block {$$ = $1;}
+ | EOL {$$.values_num = 0;}
+ ;
+
+statement_list:
+ statement_list statement
+ {
+ $$ = $1;
+ if (($2.values_num > 0) || ($2.children_num > 0))
+ {
+ $$.statement_num++;
+ $$.statement = realloc ($$.statement, $$.statement_num * sizeof (oconfig_item_t));
+ $$.statement[$$.statement_num-1] = $2;
+ }
+ }
+ | statement
+ {
+ if (($1.values_num > 0) || ($1.children_num > 0))
+ {
+ $$.statement = malloc (sizeof (oconfig_item_t));
+ $$.statement[0] = $1;
+ $$.statement_num = 1;
+ }
+ else
+ {
+ $$.statement = NULL;
+ $$.statement_num = 0;
+ }
+ }
+ ;
+
+entire_file:
+ statement_list
+ {
+ ci_root = malloc (sizeof (oconfig_item_t));
+ memset (ci_root, '\0', sizeof (oconfig_item_t));
+ ci_root->children = $1.statement;
+ ci_root->children_num = $1.statement_num;
+ }
+ ;
+
+%%
+static int yyerror (const char *s)
+{
+ char *text;
+
+ if (*yytext == '\n')
+ text = "<newline>";
+ else
+ text = yytext;
+
+ fprintf (stderr, "Parse error in file `%s', line %i near `%s': %s\n",
+ c_file, yylineno, text, s);
+ return (-1);
+} /* int yyerror */
+
+static char *unquote (const char *orig)
+{
+ char *ret = strdup (orig);
+ int len;
+ int i;
+
+ if (ret == NULL)
+ return (NULL);
+
+ len = strlen (ret);
+
+ if ((len < 2) || (ret[0] != '"') || (ret[len - 1] != '"'))
+ return (ret);
+
+ len -= 2;
+ memmove (ret, ret + 1, len);
+ ret[len] = '\0';
+
+ for (i = 0; i < len; i++)
+ {
+ if (ret[i] == '\\')
+ {
+ memmove (ret + i, ret + (i + 1), len - i);
+ len--;
+ }
+ }
+
+ return (ret);
+} /* char *unquote */
diff --git a/src/scanner.l b/src/scanner.l
--- /dev/null
+++ b/src/scanner.l
@@ -0,0 +1,137 @@
+/**
+ * oconfig - src/scanner.l
+ * Copyright (C) 2007 Florian octo Forster <octo at verplant.org>
+ * Copyright (C) 2008 Sebastian tokkee Harl <sh at tokkee.org>
+ *
+ * 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; only version 2 of the License is applicable.
+ *
+ * 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.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+%{
+#include <stdlib.h>
+#include "oconfig.h"
+#include "aux_types.h"
+#include "parser.h"
+
+/* multiline string buffer */
+static char *ml_buffer = NULL;
+static int ml_pos = 0;
+static int ml_len = 0;
+
+#define ml_free (ml_len - ml_pos)
+
+static void ml_append (char *);
+
+#ifdef yyterminate
+# undef yyterminate
+#endif
+#define yyterminate() \
+ do { free (ml_buffer); ml_buffer = NULL; ml_pos = 0; ml_len = 0; \
+ return YY_NULL; } while (0)
+%}
+%option yylineno
+%option noyywrap
+%x ML
+WHITE_SPACE [\ \t\b]
+NON_WHITE_SPACE [^\ \t\b]
+EOL (\r\n|\n)
+QUOTED_STRING ([^\\"]+|\\.)*
+UNQUOTED_STRING [0-9A-Za-z_]+
+HEX_NUMBER 0[xX][0-9a-fA-F]+
+OCT_NUMBER 0[0-7]+
+DEC_NUMBER [\+\-]?[0-9]+
+FLOAT_NUMBER [\+\-]?[0-9]*\.[0-9]+([eE][\+\-][0-9]+)?
+NUMBER ({FLOAT_NUMBER}|{HEX_NUMBER}|{OCT_NUMBER}|{DEC_NUMBER})
+BOOL_TRUE (true|yes|on)
+BOOL_FALSE (false|no|off)
+COMMENT #.*
+PORT (6(5(5(3[0-5]|[0-2][0-9])|[0-4][0-9][0-9])|[0-4][0-9][0-9][0-9])|[1-5][0-9][0-9][0-9][0-9]|[1-9][0-9]?[0-9]?[0-9]?)
+IP_BYTE (2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])
+IPV4_ADDR {IP_BYTE}\.{IP_BYTE}\.{IP_BYTE}\.{IP_BYTE}(:{PORT})?
+
+%%
+{WHITE_SPACE} |
+{COMMENT} {/* ignore */}
+
+\\{EOL} {/* continue line */}
+
+{EOL} {return (EOL);}
+"/" {return (SLASH);}
+"<" {return (OPENBRAC);}
+">" {return (CLOSEBRAC);}
+{BOOL_TRUE} {yylval.boolean = 1; return (BTRUE);}
+{BOOL_FALSE} {yylval.boolean = 0; return (BFALSE);}
+
+{IPV4_ADDR} {yylval.string = yytext; return (UNQUOTED_STRING);}
+
+{NUMBER} {yylval.number = strtod (yytext, NULL); return (NUMBER);}
+
+\"{QUOTED_STRING}\" {yylval.string = yytext; return (QUOTED_STRING);}
+{UNQUOTED_STRING} {yylval.string = yytext; return (UNQUOTED_STRING);}
+
+\"{QUOTED_STRING}\\{EOL} {
+ int len = strlen (yytext);
+
+ ml_pos = 0;
+
+ /* remove "\\<EOL>" */
+ if ('\r' == yytext[len - 2])
+ len -= 3;
+ else
+ len -= 2;
+ yytext[len] = '\0';
+
+ ml_append (yytext);
+ BEGIN (ML);
+}
+<ML>^{WHITE_SPACE}+ {/* remove leading white-space */}
+<ML>{NON_WHITE_SPACE}{QUOTED_STRING}\\{EOL} {
+ int len = strlen (yytext);
+
+ /* remove "\\<EOL>" */
+ if ('\r' == yytext[len - 2])
+ len -= 3;
+ else
+ len -= 2;
+ yytext[len] = '\0';
+
+ ml_append(yytext);
+}
+<ML>{NON_WHITE_SPACE}{QUOTED_STRING}\" {
+ ml_append(yytext);
+ yylval.string = ml_buffer;
+
+ BEGIN (INITIAL);
+ return (QUOTED_STRING);
+}
+%%
+static void ml_append (char *string)
+{
+ int len = strlen (string);
+ int s;
+
+ if (ml_free <= len) {
+ ml_len += len - ml_free + 1;
+ ml_buffer = (char *)realloc (ml_buffer, ml_len);
+ if (NULL == ml_buffer)
+ YY_FATAL_ERROR ("out of dynamic memory in ml_append");
+ }
+
+ s = snprintf (ml_buffer + ml_pos, ml_free, "%s", string);
+ if ((0 > s) || (ml_free <= s))
+ YY_FATAL_ERROR ("failed to write to multiline buffer");
+
+ ml_pos += s;
+ return;
+} /* ml_append */
+
diff --git a/src/utils_array.c b/src/utils_array.c
--- /dev/null
+++ b/src/utils_array.c
@@ -0,0 +1,95 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+
+#include "utils_array.h"
+
+struct str_array_s
+{
+ char **ptr;
+ size_t size;
+};
+
+str_array_t *array_create (void) /* {{{ */
+{
+ str_array_t *a;
+
+ a = malloc (sizeof (*a));
+ if (a == NULL)
+ return (NULL);
+
+ memset (a, 0, sizeof (*a));
+ a->ptr = NULL;
+ a->size = 0;
+
+ return (a);
+} /* }}} str_array_t *array_create */
+
+void array_destroy (str_array_t *a) /* {{{ */
+{
+ if (a == NULL)
+ return;
+
+ free (a->ptr);
+ a->ptr = NULL;
+ a->size = 0;
+
+ free (a);
+} /* }}} void array_destroy */
+
+int array_append (str_array_t *a, const char *entry) /* {{{ */
+{
+ char **ptr;
+
+ if ((entry == NULL) || (a == NULL))
+ return (EINVAL);
+
+ ptr = realloc (a->ptr, sizeof (*a->ptr) * (a->size + 1));
+ if (ptr == NULL)
+ return (ENOMEM);
+ a->ptr = ptr;
+ ptr = a->ptr + a->size;
+
+ *ptr = strdup (entry);
+ if (*ptr == NULL)
+ return (ENOMEM);
+
+ a->size++;
+ return (0);
+} /* }}} int array_append */
+
+int array_append_format (str_array_t *a, const char *format, ...) /* {{{ */
+{
+ char buffer[1024];
+ va_list ap;
+ int status;
+
+ va_start (ap, format);
+ status = vsnprintf (buffer, sizeof (buffer), format, ap);
+ va_end(ap);
+
+ if ((status < 0) || (((size_t) status) >= sizeof (buffer)))
+ return (ENOMEM);
+
+ return (array_append (a, buffer));
+} /* }}} int array_append_format */
+
+int array_argc (str_array_t *a) /* {{{ */
+{
+ if (a == NULL)
+ return (-1);
+
+ return ((int) a->size);
+} /* }}} int array_argc */
+
+char **array_argv (str_array_t *a) /* {{{ */
+{
+ if ((a == NULL) || (a->size == 0))
+ return (NULL);
+
+ return (a->ptr);
+} /* }}} char **array_argv */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/utils_array.h b/src/utils_array.h
--- /dev/null
+++ b/src/utils_array.h
@@ -0,0 +1,17 @@
+#ifndef UTILS_ARRAY_H
+#define UTILS_ARRAY_H 1
+
+struct str_array_s;
+typedef struct str_array_s str_array_t;
+
+str_array_t *array_create (void);
+void array_destroy (str_array_t *a);
+int array_append (str_array_t *a, const char *entry);
+int array_append_format (str_array_t *a, const char *format, ...)
+ __attribute__((format(printf,2,3)));
+
+int array_argc (str_array_t *);
+char **array_argv (str_array_t *);
+
+#endif /* UTILS_ARRAY_H */
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/utils_params.c b/src/utils_params.c
--- /dev/null
+++ b/src/utils_params.c
@@ -0,0 +1,259 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "utils_params.h"
+
+struct parameter_s
+{
+ char *key;
+ char *value;
+};
+typedef struct parameter_s parameter_t;
+
+static parameter_t *parameters = NULL;
+static size_t parameters_num = 0;
+static _Bool parameters_init = 0;
+
+static int parameter_add (const char *key, const char *value) /* {{{ */
+{
+ parameter_t *ptr;
+
+ if (value == NULL)
+ return (EINVAL);
+
+ ptr = realloc (parameters, sizeof (*parameters) * (parameters_num + 1));
+ if (ptr == NULL)
+ return (ENOMEM);
+ parameters = ptr;
+
+ ptr = parameters + parameters_num;
+ if (key == NULL)
+ {
+ ptr->key = NULL;
+ }
+ else
+ {
+ ptr->key = strdup (key);
+ if (ptr->key == NULL)
+ return (ENOMEM);
+ }
+
+ ptr->value = strdup (value);
+ if (ptr->value == NULL)
+ {
+ free (ptr->key);
+ return (ENOMEM);
+ }
+
+ parameters_num++;
+ return (0);
+} /* }}} int parameter_add */
+
+static char *parameter_lookup (const char *key) /* {{{ */
+{
+ size_t i;
+
+ for (i = 0; i < parameters_num; i++)
+ {
+ if ((key == NULL) && (parameters[i].key == NULL))
+ return (parameters[i].value);
+ else if ((key != NULL) && (parameters[i].key != NULL)
+ && (strcmp (key, parameters[i].key) == 0))
+ return (parameters[i].value);
+ }
+
+ return (NULL);
+} /* }}} char *parameter_lookup */
+
+static char *uri_unescape (char *string) /* {{{ */
+{
+ char *in;
+ char *out;
+
+ if (string == NULL)
+ return (NULL);
+
+ in = string;
+ out = string;
+
+ while (*in != 0)
+ {
+ if (*in == '+')
+ {
+ *out = ' ';
+ }
+ else if ((in[0] == '%')
+ && isxdigit ((int) in[1]) && isxdigit ((int) in[2]))
+ {
+ char tmpstr[3];
+ char *endptr;
+ long value;
+
+ tmpstr[0] = in[1];
+ tmpstr[1] = in[2];
+ tmpstr[2] = 0;
+
+ errno = 0;
+ endptr = NULL;
+ value = strtol (tmpstr, &endptr, /* base = */ 16);
+ if ((endptr == tmpstr) || (errno != 0))
+ {
+ *out = '?';
+ }
+ else
+ {
+ *out = (char) value;
+ }
+
+ in += 2;
+ }
+ else
+ {
+ *out = *in;
+ }
+
+ in++;
+ out++;
+ } /* while (*in != 0) */
+
+ *out = 0;
+ return (string);
+} /* }}} char *uri_unescape */
+
+static int parse_keyval (char *keyval) /* {{{ */
+{
+ char *key;
+ char *val;
+
+ val = strchr (keyval, '=');
+ if (val == NULL)
+ {
+ key = NULL;
+ val = keyval;
+ }
+ else
+ {
+ key = keyval;
+ *val = 0;
+ val++;
+ }
+
+ parameter_add (uri_unescape (key), uri_unescape (val));
+
+ return (0);
+} /* }}} int parse_keyval */
+
+static int parse_query_string (char *query_string) /* {{{ */
+{
+ char *dummy;
+ char *keyval;
+
+ if (query_string == NULL)
+ return (EINVAL);
+
+ dummy = query_string;
+ while ((keyval = strtok (dummy, ";&")) != NULL)
+ {
+ dummy = NULL;
+ parse_keyval (keyval);
+ }
+
+ return (0);
+} /* }}} int parse_query_string */
+
+int param_init (void) /* {{{ */
+{
+ const char *query_string;
+ char *copy;
+ int status;
+
+ if (parameters_init)
+ return (0);
+
+ query_string = getenv ("QUERY_STRING");
+ if (query_string == NULL)
+ return (ENOENT);
+
+ copy = strdup (query_string);
+ if (copy == NULL)
+ return (ENOMEM);
+
+ status = parse_query_string (copy);
+ free (copy);
+
+ parameters_init = 1;
+
+ return (status);
+} /* }}} int param_init */
+
+void param_finish (void) /* {{{ */
+{
+ size_t i;
+
+ if (!parameters_init)
+ return;
+
+ for (i = 0; i < parameters_num; i++)
+ {
+ free (parameters[i].key);
+ free (parameters[i].value);
+ }
+ free (parameters);
+
+ parameters = NULL;
+ parameters_num = 0;
+ parameters_init = 0;
+} /* }}} void param_finish */
+
+const char *param (const char *key) /* {{{ */
+{
+ param_init ();
+
+ return (parameter_lookup (key));
+} /* }}} const char *param */
+
+int uri_escape (char *dst, const char *src, size_t size) /* {{{ */
+{
+ size_t in;
+ size_t out;
+
+ in = 0;
+ out = 0;
+ while (42)
+ {
+ if (src[in] == 0)
+ {
+ dst[out] = 0;
+ return (0);
+ }
+ else if ((src[in] < 32)
+ || (src[in] == '&')
+ || (src[in] == ';')
+ || (src[in] >= 128))
+ {
+ char esc[4];
+
+ if ((size - out) < 4)
+ break;
+
+ snprintf (esc, sizeof (esc), "%%%02x", (unsigned int) src[in]);
+ dst[out] = esc[0];
+ dst[out+1] = esc[1];
+ dst[out+2] = esc[2];
+
+ out += 3;
+ in++;
+ }
+ else
+ {
+ dst[out] = src[in];
+ out++;
+ in++;
+ }
+ } /* while (42) */
+} /* }}} int uri_escape */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/utils_params.h b/src/utils_params.h
--- /dev/null
+++ b/src/utils_params.h
@@ -0,0 +1,11 @@
+#ifndef UTILS_PARAMS_H
+#define UTILS_PARAMS_H 1
+
+int param_init (void);
+void param_finish (void);
+
+const char *param (const char *key);
+
+int uri_escape (char *dst, const char *src, size_t size);
+
+#endif /* UTILS_PARAMS_H */
diff --git a/test.fcgi.c b/test.fcgi.c
--- a/test.fcgi.c
+++ /dev/null
@@ -1,112 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <strings.h>
-#include <errno.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <dirent.h>
-
-#include "common.h"
-#include "graph_list.h"
-#include "utils_params.h"
-
-#include "action_graph.h"
-#include "action_list_graphs.h"
-
-/* Include this last, so the macro magic of <fcgi_stdio.h> doesn't interfere
- * with our own header files. */
-#include <fcgiapp.h>
-#include <fcgi_stdio.h>
-
-struct action_s
-{
- const char *name;
- int (*callback) (void);
-};
-typedef struct action_s action_t;
-
-static int action_usage (void);
-
-static const action_t actions[] =
-{
- { "graph", action_graph },
- { "list_graphs", action_list_graphs },
- { "usage", action_usage }
-};
-static const size_t actions_num = sizeof (actions) / sizeof (actions[0]);
-
-
-static int action_usage (void) /* {{{ */
-{
- size_t i;
-
- printf ("Content-Type: text/plain\n\n");
-
- printf ("Usage:\n"
- "\n"
- " Available actions:\n"
- "\n");
-
- for (i = 0; i < actions_num; i++)
- printf (" * %s\n", actions[i].name);
-
- printf ("\n");
-
- return (0);
-} /* }}} int action_usage */
-
-static int handle_request (void) /* {{{ */
-{
- const char *action;
-
- param_init ();
-
- action = param ("action");
- if (action == NULL)
- {
- return (action_usage ());
- }
- else
- {
- size_t i;
-
- for (i = 0; i < actions_num; i++)
- {
- if (strcmp (action, actions[i].name) == 0)
- return ((*actions[i].callback) ());
- }
-
- return (action_usage ());
- }
-} /* }}} int handle_request */
-
-static int run (void) /* {{{ */
-{
- while (FCGI_Accept() >= 0)
- {
- handle_request ();
- param_finish ();
- }
-
- return (0);
-} /* }}} int run */
-
-int main (int argc, char **argv) /* {{{ */
-{
- int status;
-
- argc = 0;
- argv = NULL;
-
- if (FCGX_IsCGI ())
- status = handle_request ();
- else
- status = run ();
-
- exit ((status == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
-} /* }}} int main */
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/utils_array.c b/utils_array.c
--- a/utils_array.c
+++ /dev/null
@@ -1,95 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-
-#include "utils_array.h"
-
-struct str_array_s
-{
- char **ptr;
- size_t size;
-};
-
-str_array_t *array_create (void) /* {{{ */
-{
- str_array_t *a;
-
- a = malloc (sizeof (*a));
- if (a == NULL)
- return (NULL);
-
- memset (a, 0, sizeof (*a));
- a->ptr = NULL;
- a->size = 0;
-
- return (a);
-} /* }}} str_array_t *array_create */
-
-void array_destroy (str_array_t *a) /* {{{ */
-{
- if (a == NULL)
- return;
-
- free (a->ptr);
- a->ptr = NULL;
- a->size = 0;
-
- free (a);
-} /* }}} void array_destroy */
-
-int array_append (str_array_t *a, const char *entry) /* {{{ */
-{
- char **ptr;
-
- if ((entry == NULL) || (a == NULL))
- return (EINVAL);
-
- ptr = realloc (a->ptr, sizeof (*a->ptr) * (a->size + 1));
- if (ptr == NULL)
- return (ENOMEM);
- a->ptr = ptr;
- ptr = a->ptr + a->size;
-
- *ptr = strdup (entry);
- if (*ptr == NULL)
- return (ENOMEM);
-
- a->size++;
- return (0);
-} /* }}} int array_append */
-
-int array_append_format (str_array_t *a, const char *format, ...) /* {{{ */
-{
- char buffer[1024];
- va_list ap;
- int status;
-
- va_start (ap, format);
- status = vsnprintf (buffer, sizeof (buffer), format, ap);
- va_end(ap);
-
- if ((status < 0) || (((size_t) status) >= sizeof (buffer)))
- return (ENOMEM);
-
- return (array_append (a, buffer));
-} /* }}} int array_append_format */
-
-int array_argc (str_array_t *a) /* {{{ */
-{
- if (a == NULL)
- return (-1);
-
- return ((int) a->size);
-} /* }}} int array_argc */
-
-char **array_argv (str_array_t *a) /* {{{ */
-{
- if ((a == NULL) || (a->size == 0))
- return (NULL);
-
- return (a->ptr);
-} /* }}} char **array_argv */
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/utils_array.h b/utils_array.h
--- a/utils_array.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef UTILS_ARRAY_H
-#define UTILS_ARRAY_H 1
-
-struct str_array_s;
-typedef struct str_array_s str_array_t;
-
-str_array_t *array_create (void);
-void array_destroy (str_array_t *a);
-int array_append (str_array_t *a, const char *entry);
-int array_append_format (str_array_t *a, const char *format, ...)
- __attribute__((format(printf,2,3)));
-
-int array_argc (str_array_t *);
-char **array_argv (str_array_t *);
-
-#endif /* UTILS_ARRAY_H */
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/utils_params.c b/utils_params.c
--- a/utils_params.c
+++ /dev/null
@@ -1,259 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-
-#include "utils_params.h"
-
-struct parameter_s
-{
- char *key;
- char *value;
-};
-typedef struct parameter_s parameter_t;
-
-static parameter_t *parameters = NULL;
-static size_t parameters_num = 0;
-static _Bool parameters_init = 0;
-
-static int parameter_add (const char *key, const char *value) /* {{{ */
-{
- parameter_t *ptr;
-
- if (value == NULL)
- return (EINVAL);
-
- ptr = realloc (parameters, sizeof (*parameters) * (parameters_num + 1));
- if (ptr == NULL)
- return (ENOMEM);
- parameters = ptr;
-
- ptr = parameters + parameters_num;
- if (key == NULL)
- {
- ptr->key = NULL;
- }
- else
- {
- ptr->key = strdup (key);
- if (ptr->key == NULL)
- return (ENOMEM);
- }
-
- ptr->value = strdup (value);
- if (ptr->value == NULL)
- {
- free (ptr->key);
- return (ENOMEM);
- }
-
- parameters_num++;
- return (0);
-} /* }}} int parameter_add */
-
-static char *parameter_lookup (const char *key) /* {{{ */
-{
- size_t i;
-
- for (i = 0; i < parameters_num; i++)
- {
- if ((key == NULL) && (parameters[i].key == NULL))
- return (parameters[i].value);
- else if ((key != NULL) && (parameters[i].key != NULL)
- && (strcmp (key, parameters[i].key) == 0))
- return (parameters[i].value);
- }
-
- return (NULL);
-} /* }}} char *parameter_lookup */
-
-static char *uri_unescape (char *string) /* {{{ */
-{
- char *in;
- char *out;
-
- if (string == NULL)
- return (NULL);
-
- in = string;
- out = string;
-
- while (*in != 0)
- {
- if (*in == '+')
- {
- *out = ' ';
- }
- else if ((in[0] == '%')
- && isxdigit ((int) in[1]) && isxdigit ((int) in[2]))
- {
- char tmpstr[3];
- char *endptr;
- long value;
-
- tmpstr[0] = in[1];
- tmpstr[1] = in[2];
- tmpstr[2] = 0;
-
- errno = 0;
- endptr = NULL;
- value = strtol (tmpstr, &endptr, /* base = */ 16);
- if ((endptr == tmpstr) || (errno != 0))
- {
- *out = '?';
- }
- else
- {
- *out = (char) value;
- }
-
- in += 2;
- }
- else
- {
- *out = *in;
- }
-
- in++;
- out++;
- } /* while (*in != 0) */
-
- *out = 0;
- return (string);
-} /* }}} char *uri_unescape */
-
-static int parse_keyval (char *keyval) /* {{{ */
-{
- char *key;
- char *val;
-
- val = strchr (keyval, '=');
- if (val == NULL)
- {
- key = NULL;
- val = keyval;
- }
- else
- {
- key = keyval;
- *val = 0;
- val++;
- }
-
- parameter_add (uri_unescape (key), uri_unescape (val));
-
- return (0);
-} /* }}} int parse_keyval */
-
-static int parse_query_string (char *query_string) /* {{{ */
-{
- char *dummy;
- char *keyval;
-
- if (query_string == NULL)
- return (EINVAL);
-
- dummy = query_string;
- while ((keyval = strtok (dummy, ";&")) != NULL)
- {
- dummy = NULL;
- parse_keyval (keyval);
- }
-
- return (0);
-} /* }}} int parse_query_string */
-
-int param_init (void) /* {{{ */
-{
- const char *query_string;
- char *copy;
- int status;
-
- if (parameters_init)
- return (0);
-
- query_string = getenv ("QUERY_STRING");
- if (query_string == NULL)
- return (ENOENT);
-
- copy = strdup (query_string);
- if (copy == NULL)
- return (ENOMEM);
-
- status = parse_query_string (copy);
- free (copy);
-
- parameters_init = 1;
-
- return (status);
-} /* }}} int param_init */
-
-void param_finish (void) /* {{{ */
-{
- size_t i;
-
- if (!parameters_init)
- return;
-
- for (i = 0; i < parameters_num; i++)
- {
- free (parameters[i].key);
- free (parameters[i].value);
- }
- free (parameters);
-
- parameters = NULL;
- parameters_num = 0;
- parameters_init = 0;
-} /* }}} void param_finish */
-
-const char *param (const char *key) /* {{{ */
-{
- param_init ();
-
- return (parameter_lookup (key));
-} /* }}} const char *param */
-
-int uri_escape (char *dst, const char *src, size_t size) /* {{{ */
-{
- size_t in;
- size_t out;
-
- in = 0;
- out = 0;
- while (42)
- {
- if (src[in] == 0)
- {
- dst[out] = 0;
- return (0);
- }
- else if ((src[in] < 32)
- || (src[in] == '&')
- || (src[in] == ';')
- || (src[in] >= 128))
- {
- char esc[4];
-
- if ((size - out) < 4)
- break;
-
- snprintf (esc, sizeof (esc), "%%%02x", (unsigned int) src[in]);
- dst[out] = esc[0];
- dst[out+1] = esc[1];
- dst[out+2] = esc[2];
-
- out += 3;
- in++;
- }
- else
- {
- dst[out] = src[in];
- out++;
- in++;
- }
- } /* while (42) */
-} /* }}} int uri_escape */
-
-/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/utils_params.h b/utils_params.h
--- a/utils_params.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef UTILS_PARAMS_H
-#define UTILS_PARAMS_H 1
-
-int param_init (void);
-void param_finish (void);
-
-const char *param (const char *key);
-
-int uri_escape (char *dst, const char *src, size_t size);
-
-#endif /* UTILS_PARAMS_H */