src/action_graph.c: Send a "Last-Modified" header.
[collection4.git] / src / 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 static int get_time_args (str_array_t *args) /* {{{ */
23 {
24   const char *begin_str;
25   const char *end_str;
26   long now;
27   long begin;
28   long end;
29   char *endptr;
30   long tmp;
31
32   begin_str = param ("begin");
33   end_str = param ("end");
34
35   now = (long) time (NULL);
36
37   if (begin_str != NULL)
38   {
39     endptr = NULL;
40     errno = 0;
41     tmp = strtol (begin_str, &endptr, /* base = */ 0);
42     if ((endptr == begin_str) || (errno != 0))
43       return (-1);
44     if (tmp <= 0)
45       begin = now + tmp;
46     else
47       begin = tmp;
48   }
49   else /* if (begin_str == NULL) */
50   {
51     begin = now - 86400;
52   }
53
54   if (end_str != NULL)
55   {
56     endptr = NULL;
57     errno = 0;
58     tmp = strtol (end_str, &endptr, /* base = */ 0);
59     if ((endptr == end_str) || (errno != 0))
60       return (-1);
61     end = tmp;
62     if (tmp <= 0)
63       end = now + tmp;
64     else
65       end = tmp;
66   }
67   else /* if (end_str == NULL) */
68   {
69     end = now;
70   }
71
72   if (begin == end)
73     return (-1);
74
75   if (begin > end)
76   {
77     tmp = begin;
78     begin = end;
79     end = tmp;
80   }
81
82   array_append (args, "-s");
83   array_append_format (args, "%li", begin);
84   array_append (args, "-e");
85   array_append_format (args, "%li", end);
86
87   return (0);
88 } /* }}} int get_time_args */
89
90 static void emulate_graph (int argc, char **argv) /* {{{ */
91 {
92   int i;
93
94   printf ("rrdtool \\\n");
95   for (i = 0; i < argc; i++)
96   {
97     if (i < (argc - 1))
98       printf ("  \"%s\" \\\n", argv[i]);
99     else
100       printf ("  \"%s\"\n", argv[i]);
101   }
102 } /* }}} void emulate_graph */
103
104 static int ag_info_print (rrd_info_t *info) /* {{{ */
105 {
106   if (info->type == RD_I_VAL)
107     printf ("[info] %s = %g;\n", info->key, info->value.u_val);
108   else if (info->type == RD_I_CNT)
109     printf ("[info] %s = %lu;\n", info->key, info->value.u_cnt);
110   else if (info->type == RD_I_STR)
111     printf ("[info] %s = %s;\n", info->key, info->value.u_str);
112   else if (info->type == RD_I_INT)
113     printf ("[info] %s = %i;\n", info->key, info->value.u_int);
114   else if (info->type == RD_I_BLO)
115     printf ("[info] %s = [blob, %lu bytes];\n", info->key, info->value.u_blo.size);
116   else
117     printf ("[info] %s = [unknown type %#x];\n", info->key, info->type);
118
119   return (0);
120 } /* }}} int ag_info_print */
121
122 static int output_graph (rrd_info_t *info, /* {{{ */
123     time_t mtime)
124 {
125   rrd_info_t *img;
126
127   for (img = info; img != NULL; img = img->next)
128     if ((strcmp ("image", img->key) == 0)
129         && (img->type == RD_I_BLO))
130       break;
131
132   if (img == NULL)
133     return (ENOENT);
134
135   printf ("Content-Type: image/png\n"
136       "Content-Length: %lu\n",
137       img->value.u_blo.size);
138   if (mtime > 0)
139   {
140     char buffer[256];
141     int status;
142     
143     status = time_to_rfc1123 (mtime, buffer, sizeof (buffer));
144     if (status == 0)
145       printf ("Last-Modified: %s\n", buffer);
146   }
147   printf ("\n");
148
149   fwrite (img->value.u_blo.ptr, img->value.u_blo.size,
150       /* nmemb = */ 1, stdout);
151
152   return (0);
153 } /* }}} int output_graph */
154
155 #define OUTPUT_ERROR(...) do {             \
156   printf ("Content-Type: text/plain\n\n"); \
157   printf (__VA_ARGS__);                    \
158   return (0);                              \
159 } while (0)
160
161 int action_graph (void) /* {{{ */
162 {
163   str_array_t *args;
164   graph_config_t *cfg;
165   graph_instance_t *inst;
166   rrd_info_t *info;
167   int status;
168
169   cfg = gl_graph_get_selected ();
170   if (cfg == NULL)
171     OUTPUT_ERROR ("gl_graph_get_selected () failed.\n");
172
173   inst = inst_get_selected (cfg);
174   if (inst == NULL)
175     OUTPUT_ERROR ("inst_get_selected (%p) failed.\n", (void *) cfg);
176
177   args = array_create ();
178   if (args == NULL)
179     return (ENOMEM);
180
181   array_append (args, "graph");
182   array_append (args, "-");
183   array_append (args, "--imgformat");
184   array_append (args, "PNG");
185
186   get_time_args (args);
187
188   status = inst_get_rrdargs (cfg, inst, args);
189   if (status != 0)
190   {
191     array_destroy (args);
192     OUTPUT_ERROR ("inst_get_rrdargs failed with status %i.\n", status);
193   }
194
195   rrd_clear_error ();
196   info = rrd_graph_v (array_argc (args), array_argv (args));
197   if ((info == NULL) || rrd_test_error ())
198   {
199     printf ("Content-Type: text/plain\n\n");
200     printf ("rrd_graph_v failed: %s\n", rrd_get_error ());
201     emulate_graph (array_argc (args), array_argv (args));
202   }
203   else
204   {
205     int status;
206
207     status = output_graph (info, inst_get_mtime (inst));
208     if (status != 0)
209     {
210       rrd_info_t *ptr;
211
212       printf ("Content-Type: text/plain\n\n");
213       printf ("output_graph failed. Maybe the \"image\" info was not found?\n\n");
214
215       for (ptr = info; ptr != NULL; ptr = ptr->next)
216       {
217         ag_info_print (ptr);
218       }
219     }
220   }
221
222   if (info != NULL)
223     rrd_info_free (info);
224
225   array_destroy (args);
226   args = NULL;
227
228   return (0);
229 } /* }}} int action_graph */
230
231 /* vim: set sw=2 sts=2 et fdm=marker : */