eeab51a05190eef6f21ad2a36f9d21c174bcdd3f
[collection4.git] / graph_list.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <time.h>
5 #include <errno.h>
6 #include <assert.h>
7
8 #include "graph_list.h"
9 #include "common.h"
10
11 #define UPDATE_INTERVAL 10
12
13 static graph_list_t *graph_list = NULL;
14 static size_t graph_list_length = 0;
15 static time_t gl_last_update = 0;
16
17 /* "Safe" version of strcmp(3): Either or both pointers may be NULL. */
18 static int strcmp_s (const char *s1, const char *s2) /* {{{ */
19 {
20   if ((s1 == NULL) && (s2 == NULL))
21     return (0);
22   else if (s1 == NULL)
23     return (1);
24   else if (s2 == NULL)
25     return (-1);
26   assert ((s1 != NULL) && (s2 != NULL));
27
28   return (strcmp (s1, s2));
29 } /* }}} int strcmp_s */
30
31 static int gl_compare (const void *p0, const void *p1) /* {{{ */
32 {
33   const graph_list_t *gl0 = p0;
34   const graph_list_t *gl1 = p1;
35   int status;
36
37   status = strcmp (gl0->host, gl1->host);
38   if (status != 0)
39     return (status);
40
41   status = strcmp (gl0->plugin, gl1->plugin);
42   if (status != 0)
43     return (status);
44
45   status = strcmp_s (gl0->plugin_instance, gl1->plugin_instance);
46   if (status != 0)
47     return (status);
48
49   status = strcmp (gl0->type, gl1->type);
50   if (status != 0)
51     return (status);
52
53   return (strcmp_s (gl0->type_instance, gl1->type_instance));
54 } /* }}} int gl_compare */
55
56 static void gl_clear_entry (graph_list_t *gl) /* {{{ */
57 {
58   if (gl == NULL)
59     return;
60
61   free (gl->host);
62   free (gl->plugin);
63   free (gl->plugin_instance);
64   free (gl->type);
65   free (gl->type_instance);
66
67   gl->host = NULL;
68   gl->plugin = NULL;
69   gl->plugin_instance = NULL;
70   gl->type = NULL;
71   gl->type_instance = NULL;
72 } /* }}} void gl_clear_entry */
73
74 static void gl_clear (void) /* {{{ */
75 {
76   size_t i;
77
78   for (i = 0; i < graph_list_length; i++)
79     gl_clear_entry (graph_list + i);
80
81   free (graph_list);
82   graph_list = NULL;
83   graph_list_length = 0;
84   gl_last_update = 0;
85 } /* }}} void gl_clear */
86
87 static int gl_add_copy (graph_list_t *gl) /* {{{ */
88 {
89   graph_list_t *ptr;
90   int status;
91
92   if (gl == NULL)
93     return (EINVAL);
94
95   ptr = realloc (graph_list, sizeof (*graph_list) * (graph_list_length + 1));
96   if (ptr == NULL)
97     return (ENOMEM);
98   graph_list = ptr;
99
100   ptr = graph_list + graph_list_length;
101   memset (ptr, 0, sizeof (*ptr));
102   ptr->host = NULL;
103   ptr->plugin = NULL;
104   ptr->plugin_instance = NULL;
105   ptr->type = NULL;
106   ptr->type_instance = NULL;
107
108 #define DUP_OR_BREAK(member) do {                    \
109   ptr->member = NULL;                                \
110   if (gl->member != NULL)                            \
111   {                                                  \
112     ptr->member = strdup (gl->member);               \
113     if (ptr->member == NULL)                         \
114       break;                                         \
115   }                                                  \
116 } while (0)
117
118   status = ENOMEM;
119   do
120   {
121     DUP_OR_BREAK(host);
122     DUP_OR_BREAK(plugin);
123     DUP_OR_BREAK(plugin_instance);
124     DUP_OR_BREAK(type);
125     DUP_OR_BREAK(type_instance);
126
127     status = 0;
128   } while (0);
129
130 #undef DUP_OR_BREAK
131
132   if (status != 0)
133   {
134     free (ptr->host);
135     free (ptr->plugin);
136     free (ptr->plugin_instance);
137     free (ptr->type);
138     free (ptr->type_instance);
139     return (status);
140   }
141
142   graph_list_length++;
143   return (0);
144 } /* }}} int gl_add_copy */
145
146 static int callback_type (const char *type, void *user_data) /* {{{ */
147 {
148   graph_list_t *gl;
149   int status;
150
151   if ((type == NULL) || (user_data == NULL))
152     return (EINVAL);
153
154   gl = user_data;
155   if ((gl->type != NULL) || (gl->type_instance != NULL))
156     return (EINVAL);
157
158   gl->type = strdup (type);
159   if (gl->type == NULL)
160     return (ENOMEM);
161
162   gl->type_instance = strchr (gl->type, '-');
163   if (gl->type_instance != NULL)
164   {
165     *gl->type_instance = 0;
166     gl->type_instance++;
167   }
168
169   status = gl_add_copy (gl);
170
171   free (gl->type);
172   gl->type = NULL;
173   gl->type_instance = NULL;
174
175   return (status);
176 } /* }}} int callback_type */
177
178 static int callback_plugin (const char *plugin, void *user_data) /* {{{ */
179 {
180   graph_list_t *gl;
181   int status;
182
183   if ((plugin == NULL) || (user_data == NULL))
184     return (EINVAL);
185
186   gl = user_data;
187   if ((gl->plugin != NULL) || (gl->plugin_instance != NULL))
188     return (EINVAL);
189
190   gl->plugin = strdup (plugin);
191   if (gl->plugin == NULL)
192     return (ENOMEM);
193
194   gl->plugin_instance = strchr (gl->plugin, '-');
195   if (gl->plugin_instance != NULL)
196   {
197     *gl->plugin_instance = 0;
198     gl->plugin_instance++;
199   }
200
201   status = foreach_type (gl->host, plugin, callback_type, gl);
202
203   free (gl->plugin);
204   gl->plugin = NULL;
205   gl->plugin_instance = NULL;
206
207   return (status);
208 } /* }}} int callback_plugin */
209
210 static int callback_host (const char *host, void *user_data) /* {{{ */
211 {
212   graph_list_t *gl;
213   int status;
214
215   if ((host == NULL) || (user_data == NULL))
216     return (EINVAL);
217
218   gl = user_data;
219   if (gl->host != NULL)
220     return (EINVAL);
221
222   gl->host = strdup (host);
223   if (gl->host == NULL)
224     return (ENOMEM);
225
226   status =  foreach_plugin (host, callback_plugin, gl);
227
228   free (gl->host);
229   gl->host = NULL;
230
231   return (status);
232 } /* }}} int callback_host */
233
234 int gl_update (void) /* {{{ */
235 {
236   time_t now;
237   graph_list_t gl;
238   int status;
239
240   now = time (NULL);
241
242   if ((gl_last_update + UPDATE_INTERVAL) >= now)
243     return (0);
244
245   gl_clear ();
246
247   memset (&gl, 0, sizeof (gl));
248   gl.host = NULL;
249   gl.plugin = NULL;
250   gl.plugin_instance = NULL;
251   gl.type = NULL;
252   gl.type_instance = NULL;
253
254   status = foreach_host (callback_host, &gl);
255
256   if (graph_list_length > 1)
257     qsort (graph_list, graph_list_length, sizeof (*graph_list), gl_compare);
258
259   return (status);
260 } /* }}} int gl_update */
261
262 int gl_foreach (gl_callback callback, void *user_data) /* {{{ */
263 {
264   size_t i;
265
266   for (i = 0; i < graph_list_length; i++)
267   {
268     int status;
269
270     status = (*callback) (graph_list + i, user_data);
271     if (status != 0)
272       return (status);
273   }
274
275   return (0);
276 } /* }}} int gl_foreach */
277
278 /* vim: set sw=2 sts=2 et fdm=marker : */