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>
11 #include <rrd.h>
13 #include "common.h"
14 #include "action_graph.h"
15 #include "graph.h"
16 #include "graph_instance.h"
17 #include "graph_list.h"
18 #include "utils_cgi.h"
19 #include "utils_array.h"
21 #include <fcgiapp.h>
22 #include <fcgi_stdio.h>
24 struct graph_data_s
25 {
26 rrd_args_t *args;
27 rrd_info_t *info;
28 time_t mtime;
29 time_t expires;
30 long now;
31 long begin;
32 long end;
33 };
34 typedef struct graph_data_s graph_data_t;
36 static int get_time_args (graph_data_t *data) /* {{{ */
37 {
38 const char *begin_str;
39 const char *end_str;
40 long now;
41 long begin;
42 long end;
43 char *endptr;
44 long tmp;
46 begin_str = param ("begin");
47 end_str = param ("end");
49 now = (long) time (NULL);
50 data->now = now;
51 data->begin = now - 86400;
52 data->end = now;
54 if (begin_str != NULL)
55 {
56 endptr = NULL;
57 errno = 0;
58 tmp = strtol (begin_str, &endptr, /* base = */ 0);
59 if ((endptr == begin_str) || (errno != 0))
60 return (-1);
61 if (tmp <= 0)
62 begin = now + tmp;
63 else
64 begin = tmp;
65 }
66 else /* if (begin_str == NULL) */
67 {
68 begin = now - 86400;
69 }
71 if (end_str != NULL)
72 {
73 endptr = NULL;
74 errno = 0;
75 tmp = strtol (end_str, &endptr, /* base = */ 0);
76 if ((endptr == end_str) || (errno != 0))
77 return (-1);
78 end = tmp;
79 if (tmp <= 0)
80 end = now + tmp;
81 else
82 end = tmp;
83 }
84 else /* if (end_str == NULL) */
85 {
86 end = now;
87 }
89 if (begin == end)
90 return (-1);
92 if (begin > end)
93 {
94 tmp = begin;
95 begin = end;
96 end = tmp;
97 }
99 data->begin = begin;
100 data->end = end;
102 array_append (data->args->options, "-s");
103 array_append_format (data->args->options, "%li", begin);
104 array_append (data->args->options, "-e");
105 array_append_format (data->args->options, "%li", end);
107 return (0);
108 } /* }}} int get_time_args */
110 static void emulate_graph (int argc, char **argv) /* {{{ */
111 {
112 int i;
114 printf ("rrdtool \\\n");
115 for (i = 0; i < argc; i++)
116 {
117 if (i < (argc - 1))
118 printf (" \"%s\" \\\n", argv[i]);
119 else
120 printf (" \"%s\"\n", argv[i]);
121 }
122 } /* }}} void emulate_graph */
124 static int ag_info_print (rrd_info_t *info) /* {{{ */
125 {
126 if (info->type == RD_I_VAL)
127 printf ("[info] %s = %g;\n", info->key, info->value.u_val);
128 else if (info->type == RD_I_CNT)
129 printf ("[info] %s = %lu;\n", info->key, info->value.u_cnt);
130 else if (info->type == RD_I_STR)
131 printf ("[info] %s = %s;\n", info->key, info->value.u_str);
132 else if (info->type == RD_I_INT)
133 printf ("[info] %s = %i;\n", info->key, info->value.u_int);
134 else if (info->type == RD_I_BLO)
135 printf ("[info] %s = [blob, %lu bytes];\n", info->key, info->value.u_blo.size);
136 else
137 printf ("[info] %s = [unknown type %#x];\n", info->key, info->type);
139 return (0);
140 } /* }}} int ag_info_print */
142 static int output_graph (graph_data_t *data) /* {{{ */
143 {
144 rrd_info_t *img;
145 char time_buffer[256];
146 time_t expires;
147 int status;
149 for (img = data->info; img != NULL; img = img->next)
150 if ((strcmp ("image", img->key) == 0)
151 && (img->type == RD_I_BLO))
152 break;
154 if (img == NULL)
155 return (ENOENT);
157 printf ("Content-Type: image/png\n"
158 "Content-Length: %lu\n",
159 img->value.u_blo.size);
160 if (data->mtime > 0)
161 {
162 int status;
164 status = time_to_rfc1123 (data->mtime, time_buffer, sizeof (time_buffer));
165 if (status == 0)
166 printf ("Last-Modified: %s\n", time_buffer);
167 }
169 /* Print Expires header. */
170 if (data->end >= data->now)
171 {
172 /* The end of the timespan can be seen. */
173 long secs_per_pixel;
175 /* FIXME: Handle graphs with width != 400. */
176 secs_per_pixel = (data->end - data->begin) / 400;
178 expires = (time_t) (data->now + secs_per_pixel);
179 }
180 else /* if (data->end < data->now) */
181 {
182 expires = (time_t) (data->now + 86400);
183 }
184 status = time_to_rfc1123 (expires, time_buffer, sizeof (time_buffer));
185 if (status == 0)
186 printf ("Expires: %s\n", time_buffer);
188 printf ("\n");
190 fwrite (img->value.u_blo.ptr, img->value.u_blo.size,
191 /* nmemb = */ 1, stdout);
193 return (0);
194 } /* }}} int output_graph */
196 #define OUTPUT_ERROR(...) do { \
197 printf ("Content-Type: text/plain\n\n"); \
198 printf (__VA_ARGS__); \
199 return (0); \
200 } while (0)
202 int action_graph (void) /* {{{ */
203 {
204 graph_data_t data;
205 graph_config_t *cfg;
206 graph_instance_t *inst;
207 int status;
209 int argc;
210 char **argv;
212 cfg = gl_graph_get_selected ();
213 if (cfg == NULL)
214 OUTPUT_ERROR ("gl_graph_get_selected () failed.\n");
216 inst = inst_get_selected (cfg);
217 if (inst == NULL)
218 OUTPUT_ERROR ("inst_get_selected (%p) failed.\n", (void *) cfg);
220 data.args = ra_create ();
221 if (data.args == NULL)
222 return (ENOMEM);
224 array_append (data.args->options, "graph");
225 array_append (data.args->options, "-");
226 array_append (data.args->options, "--imgformat");
227 array_append (data.args->options, "PNG");
229 get_time_args (&data);
231 status = inst_get_rrdargs (cfg, inst, data.args);
232 if (status != 0)
233 {
234 ra_destroy (data.args);
235 OUTPUT_ERROR ("inst_get_rrdargs failed with status %i.\n", status);
236 }
238 argc = ra_argc (data.args);
239 argv = ra_argv (data.args);
240 if ((argc < 0) || (argv == NULL))
241 {
242 ra_destroy (data.args);
243 return (-1);
244 }
246 rrd_clear_error ();
247 data.info = rrd_graph_v (argc, argv);
248 if ((data.info == NULL) || rrd_test_error ())
249 {
250 printf ("Content-Type: text/plain\n\n");
251 printf ("rrd_graph_v failed: %s\n", rrd_get_error ());
252 emulate_graph (argc, argv);
253 }
254 else
255 {
256 int status;
258 data.mtime = inst_get_mtime (inst);
260 status = output_graph (&data);
261 if (status != 0)
262 {
263 rrd_info_t *ptr;
265 printf ("Content-Type: text/plain\n\n");
266 printf ("output_graph failed. Maybe the \"image\" info was not found?\n\n");
268 for (ptr = data.info; ptr != NULL; ptr = ptr->next)
269 {
270 ag_info_print (ptr);
271 }
272 }
273 }
275 if (data.info != NULL)
276 rrd_info_free (data.info);
278 ra_argv_free (argv);
279 ra_destroy (data.args);
280 data.args = NULL;
282 return (0);
283 } /* }}} int action_graph */
285 /* vim: set sw=2 sts=2 et fdm=marker : */