graph_def.c: Implement the "Stack" and "Area" options.
[collection4.git] / action_graph.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <stdint.h>
6 #include <inttypes.h>
7 #include <dirent.h> /* for PATH_MAX */
8 #include <assert.h>
9 #include <math.h>
10
11 #include <rrd.h>
12
13 #include "common.h"
14 #include "action_graph.h"
15 #include "graph_list.h"
16 #include "utils_params.h"
17 #include "utils_array.h"
18
19 #include <fcgiapp.h>
20 #include <fcgi_stdio.h>
21
22 struct data_source_s
23 {
24 };
25 typedef struct data_source_s data_source_t;
26
27 struct graph_def_s
28 {
29   data_source_t *data_sources;
30   size_t data_sources_num;
31
32   _Bool stack;
33
34   int def_num;
35 };
36 typedef struct graph_def_s graph_def_t;
37
38 static void emulate_graph (int argc, char **argv) /* {{{ */
39 {
40   int i;
41
42   printf ("rrdtool \\\n");
43   for (i = 0; i < argc; i++)
44   {
45     if (i < (argc - 1))
46       printf ("  \"%s\" \\\n", argv[i]);
47     else
48       printf ("  \"%s\"\n", argv[i]);
49   }
50 } /* }}} void emulate_graph */
51
52 static int ag_info_print (rrd_info_t *info) /* {{{ */
53 {
54   if (info->type == RD_I_VAL)
55     printf ("[info] %s = %g;\n", info->key, info->value.u_val);
56   else if (info->type == RD_I_CNT)
57     printf ("[info] %s = %lu;\n", info->key, info->value.u_cnt);
58   else if (info->type == RD_I_STR)
59     printf ("[info] %s = %s;\n", info->key, info->value.u_str);
60   else if (info->type == RD_I_INT)
61     printf ("[info] %s = %i;\n", info->key, info->value.u_int);
62   else if (info->type == RD_I_BLO)
63     printf ("[info] %s = [blob, %lu bytes];\n", info->key, info->value.u_blo.size);
64   else
65     printf ("[info] %s = [unknown type %#x];\n", info->key, info->type);
66
67   return (0);
68 } /* }}} int ag_info_print */
69
70 static int output_graph (rrd_info_t *info) /* {{{ */
71 {
72   rrd_info_t *img;
73
74   for (img = info; img != NULL; img = img->next)
75     if ((strcmp ("image", img->key) == 0)
76         && (img->type == RD_I_BLO))
77       break;
78
79   if (img == NULL)
80     return (ENOENT);
81
82   printf ("Content-Type: image/png\n"
83       "Content-Length: %lu\n"
84       "\n",
85       img->value.u_blo.size);
86   fwrite (img->value.u_blo.ptr, img->value.u_blo.size,
87       /* nmemb = */ 1, stdout);
88
89   return (0);
90 } /* }}} int output_graph */
91
92 #define OUTPUT_ERROR(...) do {             \
93   printf ("Content-Type: text/plain\n\n"); \
94   printf (__VA_ARGS__);                    \
95   return (0);                              \
96 } while (0)
97
98 int action_graph (void) /* {{{ */
99 {
100   str_array_t *args;
101   graph_config_t *cfg;
102   graph_instance_t *inst;
103   rrd_info_t *info;
104   int status;
105
106   cfg = graph_get_selected ();
107   if (cfg == NULL)
108     OUTPUT_ERROR ("graph_get_selected () failed.\n");
109
110   inst = inst_get_selected (cfg);
111   if (inst == NULL)
112     OUTPUT_ERROR ("inst_get_selected (%p) failed.\n", (void *) cfg);
113
114   args = array_create ();
115   if (args == NULL)
116     return (ENOMEM);
117
118   array_append (args, "graph");
119   array_append (args, "-");
120   array_append (args, "--imgformat");
121   array_append (args, "PNG");
122
123   status = gl_instance_get_rrdargs (cfg, inst, args);
124   if (status != 0)
125   {
126     array_destroy (args);
127     OUTPUT_ERROR ("gl_instance_get_rrdargs failed with status %i.\n", status);
128   }
129
130   rrd_clear_error ();
131   info = rrd_graph_v (array_argc (args), array_argv (args));
132   if ((info == NULL) || rrd_test_error ())
133   {
134     printf ("Content-Type: text/plain\n\n");
135     printf ("rrd_graph_v failed: %s\n", rrd_get_error ());
136     emulate_graph (array_argc (args), array_argv (args));
137   }
138   else
139   {
140     int status;
141
142     status = output_graph (info);
143     if (status != 0)
144     {
145       rrd_info_t *ptr;
146
147       printf ("Content-Type: text/plain\n\n");
148       printf ("output_graph failed. Maybe the \"image\" info was not found?\n\n");
149
150       for (ptr = info; ptr != NULL; ptr = ptr->next)
151       {
152         ag_info_print (ptr);
153       }
154     }
155   }
156
157   if (info != NULL)
158     rrd_info_free (info);
159
160   array_destroy (args);
161   args = NULL;
162
163   return (0);
164 } /* }}} int action_graph */
165
166 /* vim: set sw=2 sts=2 et fdm=marker : */