graph_def.c: Implement color config option.
[collection4.git] / graph_def.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <errno.h>
4
5 #include "graph_def.h"
6 #include "graph_config.h"
7 #include "common.h"
8 #include "oconfig.h"
9
10 #include <fcgiapp.h>
11 #include <fcgi_stdio.h>
12
13 /*
14  * Data structures
15  */
16 struct graph_def_s
17 {
18   graph_ident_t *select;
19
20   char *ds_name;
21   char *legend;
22   uint32_t color;
23
24   graph_def_t *next;
25 };
26
27 /*
28  * Private functions
29  */
30 #define DEF_CONFIG_FIELD(field) \
31 static int def_config_##field (const oconfig_item_t *ci, graph_ident_t *ident) \
32 {                                                                              \
33   char *tmp = NULL;                                                            \
34   int status = graph_config_get_string (ci, &tmp);                             \
35   if (status != 0)                                                             \
36     return (status);                                                           \
37   ident_set_##field (ident, tmp);                                              \
38   free (tmp);                                                                  \
39   return (0);                                                                  \
40 } /* }}} int def_config_field */
41
42 DEF_CONFIG_FIELD (host);
43 DEF_CONFIG_FIELD (plugin);
44 DEF_CONFIG_FIELD (plugin_instance);
45 DEF_CONFIG_FIELD (type);
46 DEF_CONFIG_FIELD (type_instance);
47
48 #undef DEF_CONFIG_FIELD
49
50 static int def_config_color (const oconfig_item_t *ci, uint32_t *ret_color) /* {{{ */
51 {
52   char *tmp;
53   char *endptr;
54   uint32_t color;
55
56   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
57     return (EINVAL);
58
59   tmp = ci->values[0].value.string;
60
61   endptr = NULL;
62   errno = 0;
63   color = (uint32_t) strtoul (tmp, &endptr, /* base = */ 16);
64   if ((errno != 0) || (endptr == tmp) || (color > 0x00ffffff))
65     return (EINVAL);
66
67   *ret_color = color;
68
69   return (0);
70 } /* }}} int def_config_color */
71
72 /*
73  * Public functions
74  */
75 graph_def_t *def_create (graph_config_t *cfg, graph_ident_t *ident, /* {{{ */
76     const char *ds_name)
77 {
78   graph_ident_t *selector;
79   graph_def_t *ret;
80
81   if ((cfg == NULL) || (ident == NULL) || (ds_name == NULL))
82     return (NULL);
83
84   selector = gl_graph_get_selector (cfg);
85   if (selector == NULL)
86     return (NULL);
87
88   ret = malloc (sizeof (*ret));
89   if (ret == NULL)
90   {
91     ident_destroy (selector);
92     return (NULL);
93   }
94   memset (ret, 0, sizeof (*ret));
95   ret->legend = NULL;
96
97   ret->ds_name = strdup (ds_name);
98   if (ret->ds_name == NULL)
99   {
100     ident_destroy (selector);
101     free (ret);
102     return (NULL);
103   }
104
105   ret->color = get_random_color ();
106   ret->next = NULL;
107
108   ret->select = ident_copy_with_selector (selector, ident,
109       IDENT_FLAG_REPLACE_ALL);
110   if (ret->select == NULL)
111   {
112     ident_destroy (selector);
113     free (ret->ds_name);
114     free (ret);
115     return (NULL);
116   }
117
118   ident_destroy (selector);
119   return (ret);
120 } /* }}} graph_def_t *def_create */
121
122 void def_destroy (graph_def_t *def) /* {{{ */
123 {
124   graph_def_t *next;
125
126   if (def == NULL)
127     return;
128
129   next = def->next;
130
131   ident_destroy (def->select);
132
133   free (def->ds_name);
134
135   free (def);
136
137   def_destroy (next);
138 } /* }}} void def_destroy */
139
140 int def_config (graph_config_t *cfg, const oconfig_item_t *ci) /* {{{ */
141 {
142   graph_ident_t *ident;
143   char *ds_name = NULL;
144   char *legend = NULL;
145   uint32_t color = 0x01000000;
146   graph_def_t *def;
147   int i;
148
149   ident = gl_graph_get_selector (cfg);
150   if (ident == NULL)
151     return (ENOMEM);
152
153   for (i = 0; i < ci->children_num; i++)
154   {
155     oconfig_item_t *child;
156
157 #define HANDLE_FIELD(name,field) \
158     else if (strcasecmp (name, child->key) == 0) \
159       def_config_##field (child, ident)
160
161     child = ci->children + i;
162     if (strcasecmp ("DSName", child->key) == 0)
163       graph_config_get_string (child, &ds_name);
164     else if (strcasecmp ("Legend", child->key) == 0)
165       graph_config_get_string (child, &legend);
166     else if (strcasecmp ("Color", child->key) == 0)
167       def_config_color (child, &color);
168
169     HANDLE_FIELD ("Host", host);
170     HANDLE_FIELD ("Plugin", plugin);
171     HANDLE_FIELD ("PluginInstance", plugin_instance);
172     HANDLE_FIELD ("Type", type);
173     HANDLE_FIELD ("TypeInstance", type_instance);
174
175 #undef HANDLE_FIELD
176   }
177
178   def = def_create (cfg, ident, ds_name);
179   if (def == NULL)
180   {
181     fprintf (stderr, "def_config: def_create failed (ds_name = %s)\n",
182         (ds_name != NULL) ? ds_name : "(null)");
183     ident_destroy (ident);
184     return (EINVAL);
185   }
186
187   def->legend = legend;
188   if (color < 0x01000000)
189     def->color = color;
190
191   ident_destroy (ident);
192   free (ds_name);
193
194   return (gl_graph_add_def (cfg, def));
195 } /* }}} int def_config */
196
197 int def_append (graph_def_t *head, graph_def_t *def) /* {{{ */
198 {
199   graph_def_t *ptr;
200
201   if ((head == NULL) || (def == NULL))
202     return (EINVAL);
203
204   ptr = head;
205   while (ptr->next != NULL)
206     ptr = ptr->next;
207
208   ptr->next = def;
209
210   return (0);
211 } /* }}} int def_append */
212
213 graph_def_t *def_search (graph_def_t *head, graph_ident_t *ident, /* {{{ */
214     const char *ds_name)
215 {
216   graph_def_t *ptr;
217
218   if ((head == NULL) || (ident == NULL) || (ds_name == NULL))
219     return (NULL);
220
221   for (ptr = head; ptr != NULL; ptr = ptr->next)
222   {
223     if (!ident_matches (ptr->select, ident))
224       continue;
225
226     if (strcmp (ptr->ds_name, ds_name) == 0)
227       return (ptr);
228   }
229
230   return (NULL);
231 } /* }}} graph_def_t *def_search */
232
233 _Bool def_matches (graph_def_t *def, graph_ident_t *ident) /* {{{ */
234 {
235   return (ident_matches (def->select, ident));
236 } /* }}} _Bool def_matches */
237
238 int def_foreach (graph_def_t *def, def_callback_t callback, /* {{{ */
239     void *user_data)
240 {
241   graph_def_t *ptr;
242
243   if ((def == NULL) || (callback == NULL))
244     return (EINVAL);
245
246   for (ptr = def; ptr != NULL; ptr = ptr->next)
247   {
248     int status;
249
250     status = (*callback) (ptr, user_data);
251     if (status != 0)
252       return (status);
253   }
254
255   return (0);
256 } /* }}} int def_foreach */
257
258 int def_get_rrdargs (graph_def_t *def, graph_ident_t *ident, /* {{{ */
259     str_array_t *args)
260 {
261   char *file;
262   int index;
263
264   if ((def == NULL) || (ident == NULL) || (args == NULL))
265     return (EINVAL);
266
267   file = ident_to_file (ident);
268   if (file == NULL)
269   {
270     DEBUG ("gl_ident_get_rrdargs: ident_to_file returned NULL.\n");
271     return (-1);
272   }
273
274   DEBUG ("gl_ident_get_rrdargs: file = %s;\n", file);
275
276   index = array_argc (args);
277
278   /* CDEFs */
279   array_append_format (args, "DEF:def_%04i_min=%s:%s:MIN",
280       index, file, def->ds_name);
281   array_append_format (args, "DEF:def_%04i_avg=%s:%s:AVERAGE",
282       index, file, def->ds_name);
283   array_append_format (args, "DEF:def_%04i_max=%s:%s:MAX",
284       index, file, def->ds_name);
285   /* VDEFs */
286   array_append_format (args, "VDEF:vdef_%04i_min=def_%04i_min,MINIMUM",
287       index, index);
288   array_append_format (args, "VDEF:vdef_%04i_avg=def_%04i_avg,AVERAGE",
289       index, index);
290   array_append_format (args, "VDEF:vdef_%04i_max=def_%04i_max,MAXIMUM",
291       index, index);
292   array_append_format (args, "VDEF:vdef_%04i_lst=def_%04i_avg,LAST",
293       index, index);
294
295   /* Graph part */
296   array_append_format (args, "LINE1:def_%04i_avg#%06"PRIx32":%s",
297       index, def->color,
298       (def->legend != NULL) ? def->legend : def->ds_name);
299   array_append_format (args, "GPRINT:vdef_%04i_min:%%lg min,", index);
300   array_append_format (args, "GPRINT:vdef_%04i_avg:%%lg avg,", index);
301   array_append_format (args, "GPRINT:vdef_%04i_max:%%lg max,", index);
302   array_append_format (args, "GPRINT:vdef_%04i_lst:%%lg last\\l", index);
303
304   free (file);
305
306   return (0);
307 } /* }}} int def_get_rrdargs */
308
309 /* vim: set sw=2 sts=2 et fdm=marker : */